diff options
Diffstat (limited to 'drivers/net/wireless/rda/rda_wlan/wlan_wext.c')
-rwxr-xr-x | drivers/net/wireless/rda/rda_wlan/wlan_wext.c | 1870 |
1 files changed, 1870 insertions, 0 deletions
diff --git a/drivers/net/wireless/rda/rda_wlan/wlan_wext.c b/drivers/net/wireless/rda/rda_wlan/wlan_wext.c new file mode 100755 index 00000000..cd32c542 --- /dev/null +++ b/drivers/net/wireless/rda/rda_wlan/wlan_wext.c @@ -0,0 +1,1870 @@ +#include "wlan_includes.h" + +static int wlan_get_name(struct net_device *dev, struct iw_request_info *info, + char *cwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + /* We could add support for 802.11n here as needed. Jean II */ + snprintf(cwrq, IFNAMSIZ, "IEEE 802.11b/g"); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + fwrq->m = (long)2437 *100000; + fwrq->e = 1; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + if (priv->connect_status == MAC_CONNECTED) { + memcpy(awrq->sa_data, priv->curbssparams.bssid, ETH_ALEN); + } else { + memset(awrq->sa_data, 0, ETH_ALEN); + } + awrq->sa_family = ARPHRD_ETHER; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + u16 val = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + val = 600; + + vwrq->value = val; + vwrq->disabled = val > WLAN_RTS_MAX_VALUE; /* min rts value is 0 */ + vwrq->fixed = 1; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return ret; +} + +static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + u16 val = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + val = 1460; + + vwrq->value = val; + vwrq->disabled = ((val < WLAN_FRAG_MIN_VALUE) + || (val > WLAN_FRAG_MAX_VALUE)); + vwrq->fixed = 1; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return ret; +} + +static int wlan_get_mode(struct net_device *dev, + struct iw_request_info *info, u32 * uwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + *uwrq = IW_MODE_INFRA; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_get_txpow(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + vwrq->value = 20; // in dbm + vwrq->fixed = 1; + vwrq->disabled = 0; + vwrq->flags = IW_TXPOW_DBM; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + u16 val = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + vwrq->disabled = 0; + + if (vwrq->flags & IW_RETRY_LONG) { + val = 7; + + /* Subtract 1 to convert try count to retry count */ + vwrq->value = val - 1; + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG; + } else { + val = 6; + + /* Subtract 1 to convert try count to retry count */ + vwrq->value = val - 1; + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; + } + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return ret; +} + +/** + * 802.11b/g supported bitrates (in 500Kb/s units) + */ +u8 wlan_bg_rates[MAX_RATES] = { 0x02, 0x04, 0x0b, 0x16, 0x0c, 0x12, 0x18, + 0x24, 0x30, 0x48, 0x60, 0x6c, 0x00, 0x00 +}; + +u16 wlan_nr_chan = 11; + +/** + * @brief Get Range Info + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 --success, otherwise fail + */ +static int wlan_get_range(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + struct iw_range *range = (struct iw_range *)extra; + int i; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + dwrq->length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + + range->min_nwid = 0; + range->max_nwid = 0; + + range->num_bitrates = sizeof(wlan_bg_rates); + for (i = 0; i < range->num_bitrates; i++) + range->bitrate[i] = wlan_bg_rates[i] * 500000; + range->num_bitrates = i; + + range->num_frequency = 0; + + range->scan_capa = IW_SCAN_CAPA_ESSID; + + for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES) + && (i < wlan_nr_chan); i++) { + range->freq[range->num_frequency].i = (long)(i + 1); + range->freq[range->num_frequency].m = + (long)((2412 + 5 * i) * 100000); + range->freq[range->num_frequency].e = 1; + range->num_frequency++; + } + + range->num_channels = range->num_frequency; + + /* + * Set an indication of the max TCP throughput in bit/s that we can + * expect using this interface + */ + range->throughput = 5000 * 1000; + + range->min_rts = WLAN_RTS_MIN_VALUE; + range->max_rts = WLAN_RTS_MAX_VALUE; + range->min_frag = WLAN_FRAG_MIN_VALUE; + range->max_frag = WLAN_FRAG_MAX_VALUE; + + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + range->num_encoding_sizes = 2; + range->max_encoding_tokens = 4; + + /* + * Right now we support only "iwconfig ethX power on|off" + */ + range->pm_capa = IW_POWER_ON; + + /* + * Minimum version we recommend + */ + range->we_version_source = 15; + + /* + * Version we are compiled with + */ + range->we_version_compiled = WIRELESS_EXT; + + range->retry_capa = IW_RETRY_LIMIT; + range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + + range->min_retry = 0; + range->max_retry = 14; + + /* + * Set the qual, level and noise range values + */ + range->max_qual.qual = 100; + range->max_qual.level = 0; + range->max_qual.noise = 0; + range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + + range->avg_qual.qual = 70; + /* TODO: Find real 'good' to 'bad' threshold value for RSSI */ + range->avg_qual.level = 0; + range->avg_qual.noise = 0; + range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + + range->sensitivity = 0; + + /* Setup the supported power level ranges */ + memset(range->txpower, 0, sizeof(range->txpower)); + range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE; + range->txpower[0] = 0; + range->txpower[1] = 20; + range->num_txpower = 2; + + range->event_capa[0] = (IW_EVENT_CAPA_K_0 | + IW_EVENT_CAPA_MASK(SIOCGIWAP) | + IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); + range->event_capa[1] = IW_EVENT_CAPA_K_1; + + range->enc_capa = IW_ENC_CAPA_WPA + | IW_ENC_CAPA_WPA2 + | IW_ENC_CAPA_CIPHER_TKIP + | IW_ENC_CAPA_CIPHER_CCMP; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_set_power(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_get_power(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + vwrq->value = 0; + vwrq->flags = 0; + vwrq->disabled = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_update_bss_stats(wlan_private * priv) +{ + int ret = -1; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + memcpy(priv->curbssparams.ssid, + priv->assoc_ssid, sizeof(priv->curbssparams.ssid)); + + if (priv->scan_running == WLAN_SCAN_RUNNING) + return 0; + + ret = wlan_get_bssid(priv, priv->curbssparams.bssid); + if (ret) { + WLAN_ERRP("wlan_get_bssid, ret = %d\n", ret); + goto out; + } + + ret = wlan_get_rssi(priv, &priv->curbssparams.rssi); + if (ret) { + WLAN_ERRP("wlan_get_rssi, ret = %d\n", ret); + goto out; + } + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<< ch = %d rssi = %d\n", + __func__, priv->curbssparams.channel, + priv->curbssparams.rssi); + +out: + return ret; +} + +static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int stats_valid = 0; + u8 snr; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + if (priv->connect_status != MAC_CONNECTED) + goto out; + + wlan_update_bss_stats(priv); + + priv->wstats.miss.beacon = 0; + priv->wstats.discard.retries = 0; + priv->wstats.qual.level = 0x100 + (s8)priv->curbssparams.rssi; + + snr = priv->wstats.qual.level - WLAN_NF_DEFAULT_SCAN_VALUE; + priv->wstats.qual.qual = + (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - snr) * + (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - snr))) / + (RSSI_DIFF * RSSI_DIFF); + if (priv->wstats.qual.qual > 100) + priv->wstats.qual.qual = 100; + priv->wstats.qual.noise = WLAN_NF_DEFAULT_SCAN_VALUE; + priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + + stats_valid = 1; + +out: + if (!stats_valid) { + priv->wstats.miss.beacon = 0; + priv->wstats.discard.retries = 0; + priv->wstats.qual.qual = 0; + priv->wstats.qual.level = 0; + priv->wstats.qual.noise = 0; + priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED; + priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID | + IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; + } + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return &priv->wstats; +} + +static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + vwrq->fixed = 0; + vwrq->value = 54*1000; + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return ret; +} + +static int wlan_set_mode(struct net_device *dev, + struct iw_request_info *info, u32 * uwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +/** + * @brief Get Encryption key + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 --success, otherwise fail + */ +static int wlan_get_encode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, u8 * extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +/** + * @brief Set Encryption key + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 --success, otherwise fail + */ +static int wlan_set_encode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +/** + * @brief Set Encryption key (internal) + * + * @param priv A pointer to private card structure + * @param key_material A pointer to key material + * @param key_length length of key material + * @param index key index to set + * @param set_tx_key Force set TX key (1 = yes, 0 = no) + * @return 0 --success, otherwise fail + */ +static int copy_wep_key(wlan_private * priv, + const char *key_material, + u16 key_length, u16 index, int set_tx_key) +{ + int ret = 0; + struct enc_key *pkey; + + /* Paranoid validation of key index */ + if (index > 3) { + ret = -EINVAL; + goto out; + } + + /* validate max key length */ + if (key_length > KEY_LEN_WEP_104) { + ret = -EINVAL; + goto out; + } + + if (key_length == KEY_LEN_WEP_40) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "WEP40 : %02x%02x%02x%02x%02x\n", + key_material[0], key_material[1], key_material[2], + key_material[3], key_material[4]); + } else if (key_length == KEY_LEN_WEP_104) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "WEP104 : %02x%02x%02x%02x%02x" + " %02x%02x%02x%02x%02x" + " %02x%02x%02x\n", + key_material[0], key_material[1], key_material[2], + key_material[3], key_material[4], key_material[5], + key_material[6], key_material[7], key_material[8], + key_material[9], key_material[10], key_material[11], + key_material[12]); + } else { + WLAN_ERRP("Error in WEP Key length %d\n", key_length); + } + + pkey = &priv->wep_keys[index]; + + if (key_length > 0) { + memset(pkey, 0, sizeof(struct enc_key)); + pkey->type = KEY_TYPE_ID_WEP; + + /* Standardize the key length */ + pkey->len = (key_length > KEY_LEN_WEP_40) ? + KEY_LEN_WEP_104 : KEY_LEN_WEP_40; + memcpy(pkey->key, key_material, key_length); + } + + if (set_tx_key) { + /* Ensure the chosen key is valid */ + if (!pkey->len) { + WLAN_ERRP("key not set, so cannot enable it\n"); + ret = -EINVAL; + goto out; + } + priv->wep_tx_keyidx = index; + } + + priv->secinfo.wep_enabled = 1; + +out: + return ret; +} + +static int validate_key_index(u16 def_index, u16 raw_index, + u16 * out_index, u16 * is_default) +{ + if (!out_index || !is_default) + return -EINVAL; + + /* Verify index if present, otherwise use default TX key index */ + if (raw_index > 0) { + if (raw_index > 4) + return -EINVAL; + *out_index = raw_index - 1; + } else { + *out_index = def_index; + *is_default = 1; + } + return 0; +} + +static void disable_wep(wlan_private * priv) +{ + int i; + + /* Set Open System auth mode */ + priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; + + /* Clear WEP keys and mark WEP as disabled */ + priv->secinfo.wep_enabled = 0; + for (i = 0; i < 4; i++) + priv->wep_keys[i].len = 0; +} + +static void disable_wpa(wlan_private * priv) +{ + memset(&priv->wpa_mcast_key, 0, sizeof(struct enc_key)); + priv->wpa_mcast_key.flags = KEY_INFO_WPA_MCAST; + + memset(&priv->wpa_unicast_key, 0, sizeof(struct enc_key)); + priv->wpa_unicast_key.flags = KEY_INFO_WPA_UNICAST; + + priv->secinfo.WPAenabled = 0; + priv->secinfo.WPA2enabled = 0; + priv->secinfo.cipther_type = 0; + priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; +} + +/** + * @brief Get Extended Encryption key (WPA/802.1x and WEP) + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 on success, otherwise failure + */ +static int wlan_get_encodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = -EINVAL; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int index, max_key_len; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + max_key_len = dwrq->length - sizeof(*ext); + if (max_key_len < 0) + goto out; + + index = dwrq->flags & IW_ENCODE_INDEX; + if (index) { + if (index < 1 || index > 4) + goto out; + index--; + } else { + index = priv->wep_tx_keyidx; + } + + if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) && + ext->alg != IW_ENCODE_ALG_WEP) { + if (index != 0) + goto out; + } + + dwrq->flags = index + 1; + memset(ext, 0, sizeof(*ext)); + + if (!priv->secinfo.wep_enabled + && !priv->secinfo.WPAenabled + && !priv->secinfo.WPA2enabled) { + ext->alg = IW_ENCODE_ALG_NONE; + ext->key_len = 0; + dwrq->flags |= IW_ENCODE_DISABLED; + } else { + u8 *key = NULL; + + if (priv->secinfo.wep_enabled + && !priv->secinfo.WPAenabled + && !priv->secinfo.WPA2enabled) { + /* WEP */ + ext->alg = IW_ENCODE_ALG_WEP; + ext->key_len = priv->wep_keys[index].len; + key = &priv->wep_keys[index].key[0]; + } else if (!priv->secinfo.wep_enabled + && (priv->secinfo.WPAenabled || + priv->secinfo.WPA2enabled)) { + /* WPA */ + struct enc_key *pkey = NULL; + + if (priv->wpa_mcast_key.len + && (priv->wpa_mcast_key. + flags & KEY_INFO_WPA_ENABLED)) + pkey = &priv->wpa_mcast_key; + else if (priv->wpa_unicast_key.len + && (priv->wpa_unicast_key. + flags & KEY_INFO_WPA_ENABLED)) + pkey = &priv->wpa_unicast_key; + + if (pkey) { + if (pkey->type == KEY_TYPE_ID_AES) { + ext->alg = IW_ENCODE_ALG_CCMP; + } else { + ext->alg = IW_ENCODE_ALG_TKIP; + } + ext->key_len = pkey->len; + key = &pkey->key[0]; + } else { + ext->alg = IW_ENCODE_ALG_TKIP; + ext->key_len = 0; + } + } else { + goto out; + } + + if (ext->key_len > max_key_len) { + ret = -E2BIG; + goto out; + } + + if (ext->key_len) + memcpy(ext->key, key, ext->key_len); + else + dwrq->flags |= IW_ENCODE_NOKEY; + dwrq->flags |= IW_ENCODE_ENABLED; + } + ret = 0; + +out: + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +/** + * @brief Set Encryption key Extended (WPA/802.1x and WEP) + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 --success, otherwise fail + */ +static int wlan_set_encodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int alg = ext->alg; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "NO SEC\n"); + + if (priv->imode != 3 && priv->imode != 5) + disable_wep(priv); + disable_wpa(priv); + } else if (alg == IW_ENCODE_ALG_WEP) { + u16 is_default = 0, index, set_tx_key = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "WEP, flags = 0x%04x\n", dwrq->flags); + + ret = validate_key_index(priv->wep_tx_keyidx, + (dwrq->flags & IW_ENCODE_INDEX), + &index, &is_default); + if (ret) + goto out; + + /* If WEP isn't enabled, or if there is no key data but a valid + * index, or if the set-TX-key flag was passed, set the TX key. + */ + if (!priv->secinfo.wep_enabled + || (dwrq->length == 0 && !is_default) + || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) + set_tx_key = 1; + + /* Copy key to driver */ + ret = copy_wep_key(priv, ext->key, ext->key_len, index, set_tx_key); + if (ret) + goto out; + + if (dwrq->flags & IW_ENCODE_RESTRICTED) { + priv->secinfo.auth_mode = IW_AUTH_ALG_SHARED_KEY; + } else if (dwrq->flags & IW_ENCODE_OPEN) { + priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; + } + + } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) { + struct enc_key *pkey; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "TKIP or CCMP, flags = 0x%04x, alg = %d\n", + dwrq->flags, alg); + + /* validate key length */ + if (((alg == IW_ENCODE_ALG_TKIP) + && (ext->key_len != KEY_LEN_WPA_TKIP)) + || ((alg == IW_ENCODE_ALG_CCMP) + && (ext->key_len != KEY_LEN_WPA_AES))) { + WLAN_ERRP("invalid size %d for key of alg, type %d\n", + ext->key_len, alg); + ret = -EINVAL; + goto out; + } + + /* Copy key to driver */ + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + pkey = &priv->wpa_mcast_key; + } else { + pkey = &priv->wpa_unicast_key; + } + + memset(pkey, 0, sizeof(struct enc_key)); + memcpy(pkey->key, ext->key, ext->key_len); + pkey->len = ext->key_len; + if (pkey->len) + pkey->flags |= KEY_INFO_WPA_ENABLED; + + /* Do this after zeroing key structure */ + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + pkey->flags |= KEY_INFO_WPA_MCAST; + } else { + pkey->flags |= KEY_INFO_WPA_UNICAST; + } + + if (alg == IW_ENCODE_ALG_TKIP) { + pkey->type = KEY_TYPE_ID_TKIP; + if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) + && !(priv->imode & (BIT6))) { + WLAN_ERRP("imode [0x%x] not match with cipher alg TKIP\n", + priv->imode); + } + } else if (alg == IW_ENCODE_ALG_CCMP) { + pkey->type = KEY_TYPE_ID_AES; + if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) + && !(priv->imode & (BIT5))) { + WLAN_ERRP("imode [0x%x] not match with cipher alg CCMP\n", + priv->imode); + } + } + + /* If WPA isn't enabled yet, do that now */ + if (priv->secinfo.WPAenabled == 0 + && priv->secinfo.WPA2enabled == 0) { + priv->secinfo.WPAenabled = 1; + priv->secinfo.WPA2enabled = 1; + } + + /* Set Keys to MAC */ + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + /* Set GTK */ + ret = wlan_set_gtk(priv, (dwrq->flags & IW_ENCODE_INDEX) - 1, ext->tx_seq, IW_ENCODE_SEQ_MAX_SIZE, pkey->key, pkey->len); + if (ret) + goto out; + } else { + pkey->flags |= KEY_INFO_WPA_UNICAST; + /* Set PTK */ + ret = wlan_set_ptk(priv, pkey->key, pkey->len); + if (ret) + goto out; + } + + /* Only disable wep if necessary: can't waste time here. */ + disable_wep(priv); + } else if (alg == IW_ENCODE_ALG_SM4) { //wapi + if (ext->key_len != 32) + goto out; + + priv->is_wapi = 1; + + /* Set Keys to MAC */ + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + unsigned char tmp[8]; + /* Set GTK */ + /* + * + * need to toggle among 1, 2, 3 + */ + ret = wlan_set_gtk(priv, (dwrq->flags & IW_ENCODE_INDEX) - 1, tmp, IW_ENCODE_SEQ_MAX_SIZE, ext->key, ext->key_len); + if (ret) + goto out; + } else { + /* Set PTK */ + ret = wlan_set_ptk(priv, ext->key, ext->key_len); + if (ret) + goto out; + } + } + +out: + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +/** + * @brief PMKSA cache operation (WPA/802.1x and WEP) + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 on success, otherwise failure + */ +static int wlan_set_pmksa(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + +static int wlan_set_genie(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + if(priv->version == WLAN_VERSION_91_E|| priv->version == WLAN_VERSION_91_F){ + unsigned char ie_len; + //huanglei add wps + ie_len = extra[1] + 2; + wlan_generic_set_str(priv, WID_GEN_ASSOC_IE, extra ,ie_len); + } + + if (extra[0] == 0x44) //wapi ie + { + unsigned char ie_len = extra[1] + 2; + wlan_generic_set_str(priv, WID_WAPI_ASSOC_IE, extra, ie_len); + goto out; + } + + if (dwrq->length > MAX_WPA_IE_LEN || (dwrq->length && extra == NULL)) { + ret = -EINVAL; + goto out; + } + + if (dwrq->length) { + memcpy(&priv->wpa_ie[0], extra, dwrq->length); + priv->wpa_ie_len = dwrq->length; + } else { + memset(&priv->wpa_ie[0], 0, sizeof(priv->wpa_ie)); + priv->wpa_ie_len = 0; + } + +out: + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return ret; +} + +static int wlan_get_genie(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + if (priv->wpa_ie_len == 0) { + dwrq->length = 0; + goto out; + } + + if (dwrq->length < priv->wpa_ie_len) { + ret = -E2BIG; + goto out; + } + + dwrq->length = priv->wpa_ie_len; + memcpy(extra, &priv->wpa_ie[0], priv->wpa_ie_len); + +out: + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return ret; +} + +static int wlan_set_auth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "flags = 0x%04x, value = 0x%x\n", dwrq->flags, dwrq->value); + + switch (dwrq->flags & IW_AUTH_INDEX) { + case IW_AUTH_CIPHER_PAIRWISE: + if (dwrq->value & (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "WEP Selected \n"); + priv->secinfo.wep_enabled = 1; + if (dwrq->value & IW_AUTH_CIPHER_WEP104) + priv->secinfo.cipther_type |= IW_AUTH_CIPHER_WEP104; + else if (dwrq->value & IW_AUTH_CIPHER_WEP40) + priv->secinfo.cipther_type |= IW_AUTH_CIPHER_WEP40; + } + if (dwrq->value & IW_AUTH_CIPHER_TKIP) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "IW_AUTH_CIPHER_TKIP \n"); + priv->secinfo.cipther_type |= IW_AUTH_CIPHER_TKIP; + } + if (dwrq->value & IW_AUTH_CIPHER_CCMP) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "IW_AUTH_CIPHER_CCMP \n"); + priv->secinfo.cipther_type |= IW_AUTH_CIPHER_CCMP; + } + if (dwrq->value & IW_AUTH_CIPHER_NONE) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "OPEN System \n"); + priv->secinfo.cipther_type = IW_AUTH_CIPHER_NONE; + } + break; + + case IW_AUTH_TKIP_COUNTERMEASURES: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_DROP_UNENCRYPTED: + /* + * wlan does not use these parameters + */ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "DO NOT USE\n"); + break; + + case IW_AUTH_KEY_MGMT: + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "KEY_MGMT, val = %d\n", dwrq->value); + priv->secinfo.key_mgmt = dwrq->value; + break; + + case IW_AUTH_WPA_VERSION: + if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "WPA_VERSION, DISABLED\n"); + priv->secinfo.WPAenabled = 0; + priv->secinfo.WPA2enabled = 0; + disable_wpa(priv); + } + if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "WPA_VERSION, WPA\n"); + priv->secinfo.WPAenabled = 1; + priv->secinfo.wep_enabled = 0; + priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; + } + if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "WPA_VERSION, WPA2\n"); + priv->secinfo.WPA2enabled = 1; + priv->secinfo.wep_enabled = 0; + priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; + } + break; + + case IW_AUTH_80211_AUTH_ALG: + if (dwrq->value & IW_AUTH_ALG_SHARED_KEY || + dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) { + if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "80211_AUTH_ALG, SHARED_KEY\n"); + priv->secinfo.auth_mode |= IW_AUTH_ALG_SHARED_KEY; + } + if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "80211_AUTH_ALG, OPEN\n"); + priv->secinfo.auth_mode |= IW_AUTH_ALG_OPEN_SYSTEM; + } + } else if (dwrq->value & IW_AUTH_ALG_LEAP) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "80211_AUTH_ALG, LEAP\n"); + priv->secinfo.auth_mode = IW_AUTH_ALG_LEAP; + } else if (dwrq->value & IW_AUTH_ALG_WAPI) { + priv->secinfo.auth_mode = IW_AUTH_ALG_WAPI; + } else { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "80211_AUTH_ALG, unknown\n"); + ret = -EINVAL; + } + break; + + case IW_AUTH_WPA_ENABLED: + if (dwrq->value) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "WPA_ENABLED, value = 0x%x\n", dwrq->value); + if (!priv->secinfo.WPAenabled && + !priv->secinfo.WPA2enabled) { + priv->secinfo.WPAenabled = 1; + priv->secinfo.WPA2enabled = 1; + priv->secinfo.wep_enabled = 0; + priv->secinfo.auth_mode = IW_AUTH_ALG_OPEN_SYSTEM; + } + } else { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "WPA_ENABLED, value = ZERO\n"); + priv->secinfo.WPAenabled = 0; + priv->secinfo.WPA2enabled = 0; + disable_wpa(priv); + } + break; + + case IW_AUTH_WAPI_ENABLED: + if (dwrq->value & BIT1) { + disable_wpa(priv); + disable_wep(priv); + priv->secinfo.auth_mode = IW_AUTH_ALG_WAPI; + } else if (dwrq->value & BIT2) { + disable_wpa(priv); + disable_wep(priv); + priv->secinfo.auth_mode = IW_AUTH_ALG_WAPI; + } + break; + + default: + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "NOT SUPPORT\n"); + ret = -EOPNOTSUPP; + break; + } + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return ret; +} + +static int wlan_get_auth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + + switch (dwrq->flags & IW_AUTH_INDEX) { + case IW_AUTH_KEY_MGMT: + dwrq->value = priv->secinfo.key_mgmt; + break; + + case IW_AUTH_WPA_VERSION: + dwrq->value = 0; + if (priv->secinfo.WPAenabled) + dwrq->value |= IW_AUTH_WPA_VERSION_WPA; + if (priv->secinfo.WPA2enabled) + dwrq->value |= IW_AUTH_WPA_VERSION_WPA2; + if (!dwrq->value) + dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED; + break; + + case IW_AUTH_80211_AUTH_ALG: + dwrq->value = priv->secinfo.auth_mode; + break; + + case IW_AUTH_WPA_ENABLED: + if (priv->secinfo.WPAenabled && priv->secinfo.WPA2enabled) + dwrq->value = 1; + break; + + default: + ret = -EOPNOTSUPP; + } + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + return ret; +} + +static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + return 0; +} + +static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + + memcpy(extra, priv->curbssparams.ssid, strlen(priv->curbssparams.ssid)); + dwrq->length = strlen(priv->curbssparams.ssid); + extra[dwrq->length] = '\0'; + + /* + * If none, we may want to get the one that was set + */ + + dwrq->flags = 1; /* active */ + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>> \n", __func__); + return 0; +} + +void wlan_indicate_disconnected(wlan_private * priv) +{ + union iwreq_data wrqu; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_NORM, "%s <<<\n", __func__); + + memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->netDev, SIOCGIWAP, &wrqu, NULL); + + /*report disconnect to upper layer */ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_NORM, "%s >>>\n", __func__); +} + +void wlan_indicate_connected(wlan_private * priv) +{ + union iwreq_data wrqu; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_NORM, "%s <<<\n", __func__); + + memcpy(wrqu.ap_addr.sa_data, priv->curbssparams.bssid, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->netDev, SIOCGIWAP, &wrqu, NULL); + + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_NORM, "%s >>> \n connect mac: %2x:%2x:%2x:%2x:%2x:%2x \n", + __func__, priv->curbssparams.bssid[0], + priv->curbssparams.bssid[1], priv->curbssparams.bssid[2], + priv->curbssparams.bssid[3], priv->curbssparams.bssid[4], + priv->curbssparams.bssid[5]); +} + +struct bss_descriptor *get_bss_desc_from_scanlist(wlan_private * priv, + unsigned char *bssid) +{ + struct bss_descriptor *iter_bss; + struct bss_descriptor *ret_bss = NULL; + + spin_lock(&priv->ScanListLock); + /* report all bss to upper layer */ + list_for_each_entry(iter_bss, &priv->network_list, list) { + if (memcmp(iter_bss->bssid, bssid, 6) == 0) { + ret_bss = iter_bss; + break; + } + } + spin_unlock(&priv->ScanListLock); + return ret_bss; +} + +static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + u8 ssid[IW_ESSID_MAX_SIZE + 1]; + u8 ssid_len = 0; + int in_ssid_len = dwrq->length; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + /* Check the size of the string */ + if (in_ssid_len > IW_ESSID_MAX_SIZE) { + ret = -E2BIG; + goto out; + } + + memset(&ssid, 0, sizeof(ssid)); + + if (!dwrq->flags || !in_ssid_len) { + /* "any" SSID requested; leave SSID blank */ + } else { + /* Specific SSID requested */ + memcpy(&ssid, extra, in_ssid_len); + ssid[in_ssid_len] = '\0'; + ssid_len = in_ssid_len; + } + + if (!ssid_len) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "requested any SSID\n"); + } else { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "requested SSID len = %d ssid:%s\n", + ssid_len, ssid); + } + + if (ssid_len) { + memcpy(&priv->assoc_ssid[0], ssid, sizeof(ssid)); + priv->assoc_ssid_len = ssid_len; +#if 0 + priv->ToggalAssociation = FALSE; + + if (priv->StartAssociationTimeOut.timer_is_canceled) + wlan_mod_timer(&priv->StartAssociationTimeOut, 100); + priv->assoc_ongoing = TRUE; +#endif + } + +out: + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return 0; +} + + +/** + * @brief Connect to the AP or Ad-hoc Network with specific bssid + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param awrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * @return 0 --success, otherwise fail + */ + +static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + unsigned char *ap_addr = NULL; + wlan_private *priv = (wlan_private *) netdev_priv(dev); + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<< \n", __func__); + + ap_addr = awrq->sa_data; + if (!is_zero_eth_addr(ap_addr)) { + priv->reassoc_count = 0; + if (memcmp(priv->assoc_bssid, ap_addr, 6)) { + memcpy(priv->assoc_bssid, ap_addr, 6); + priv->ToggalAssociation = FALSE; + if (!priv->ReAssociationTimeOut.timer_is_canceled) { + wlan_cancel_timer(&priv->ReAssociationTimeOut); + } + if (priv->StartAssociationTimeOut.timer_is_canceled) + wlan_mod_timer(&priv->StartAssociationTimeOut, 100); + } else { + if (priv->ReAssociationTimeOut.timer_is_canceled) { + wlan_mod_timer(&priv->StartAssociationTimeOut, 100); + } + } + priv->assoc_ongoing = TRUE; + } else { + memcpy(priv->assoc_bssid, ap_addr, 6); + wlan_cancel_timer(&priv->ReAssociationTimeOut); + wlan_cancel_timer(&priv->StartAssociationTimeOut); + + disable_wep(priv); + disable_wpa(priv); + } + + WLAN_ERRP("%s <<< \n connect mac: %2x:%2x:%2x:%2x:%2x:%2x \n", __func__, + ap_addr[0], ap_addr[1], ap_addr[2], ap_addr[3], ap_addr[4], ap_addr[5]); + + return 0; +} + +unsigned char num_2_char(unsigned char num) +{ + if (num >= 0 && num <= 9) { + return '0' + num; + } else + return 'a' + (num - 0x0a); +} + +void num_2_str(unsigned char num, unsigned char *str) +{ + *str = num_2_char((num >> 4) & 0x0f); + *(str + 1) = num_2_char(num & 0x0f); +} + +static char *translate_scan(wlan_private * priv, + struct iw_request_info *info, + char *start, char *stop, + struct bss_descriptor *bss_desc) +{ + + struct iw_event iwe; /* Temporary buffer */ + u8 snr; + struct bss_descriptor *bss = bss_desc; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "translate_scan, ssid = %s ssi=%d ssid_len=%d \n", bss->ssid, bss->rssi, bss->ssid_len); + + /* First entry *MUST* be the BSSID */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); + + /* SSID */ + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + iwe.u.data.length = bss->ssid_len; + start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid); + + /* Mode */ + iwe.cmd = SIOCGIWMODE; + iwe.u.mode = bss->mode; + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN); + + /* Frequency */ + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = (2412 + 5 * (bss->channel - 1)) * 100000; + iwe.u.freq.e = 1; + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); + + /* Add quality statistics */ + iwe.cmd = IWEVQUAL; + iwe.u.qual.updated = IW_QUAL_ALL_UPDATED; + iwe.u.qual.level = 0x100 + wlan_get_aver_rssi(priv, bss->bssid); + + snr = iwe.u.qual.level - WLAN_NF_DEFAULT_SCAN_VALUE; + iwe.u.qual.qual = + (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - snr) * + (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - snr))) / + (RSSI_DIFF * RSSI_DIFF); + if (iwe.u.qual.qual > 100) + iwe.u.qual.qual = 100; + iwe.u.qual.noise = WLAN_NF_DEFAULT_SCAN_VALUE; + start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); + + /* Add encryption capability */ + iwe.cmd = SIOCGIWENCODE; + if (bss->capability & WLAN_CAPABILITY_PRIVACY) { + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + } else { + iwe.u.data.flags = IW_ENCODE_DISABLED; + } + iwe.u.data.length = 0; + start = iwe_stream_add_point(info, start, stop, &iwe, bss->ssid); + + memset(&iwe, 0, sizeof(iwe)); + if (bss_desc->wpa_ie_len && !bss_desc->wapi_ie_len) { + char buf[MAX_WPA_IE_LEN]; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "translate_scan, wpa_ie, len %d\n", + bss_desc->wpa_ie_len); + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "%02x %02x %02x %02x ... ... %02x %02x %02x %02x\n", + bss_desc->wpa_ie[0], bss_desc->wpa_ie[1], + bss_desc->wpa_ie[2], bss_desc->wpa_ie[3], + bss_desc->wpa_ie[bss_desc->wpa_ie_len - 4], + bss_desc->wpa_ie[bss_desc->wpa_ie_len - 3], + bss_desc->wpa_ie[bss_desc->wpa_ie_len - 2], + bss_desc->wpa_ie[bss_desc->wpa_ie_len - 1]); + + memcpy(buf, bss->wpa_ie, bss->wpa_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = bss_desc->wpa_ie_len; + start = iwe_stream_add_point(info, start, stop, &iwe, buf); + } + + memset(&iwe, 0, sizeof(iwe)); + if (bss_desc->rsn_ie_len) { + char buf[MAX_WPA_IE_LEN]; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "translate_scan, rsn_ie, len %d\n", + bss_desc->rsn_ie_len); + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "%02x %02x %02x %02x ... ... %02x %02x %02x %02x\n", + bss_desc->rsn_ie[0], bss_desc->rsn_ie[1], + bss_desc->rsn_ie[2], bss_desc->rsn_ie[3], + bss_desc->rsn_ie[bss_desc->rsn_ie_len - 4], + bss_desc->rsn_ie[bss_desc->rsn_ie_len - 3], + bss_desc->rsn_ie[bss_desc->rsn_ie_len - 2], + bss_desc->rsn_ie[bss_desc->rsn_ie_len - 1]); + + memcpy(buf, bss->rsn_ie, bss->rsn_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = bss_desc->rsn_ie_len; + start = iwe_stream_add_point(info, start, stop, &iwe, buf); + } + if(priv->version == WLAN_VERSION_91_E|| priv->version == WLAN_VERSION_91_F){ + /* huanglei add for wps */ + memset(&iwe, 0, sizeof(iwe)); + if (bss_desc->wps_ie_len ) { + char buf[MAX_WPS_IE_LEN]; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "translate_scan, wps_ie, len %d\n", bss_desc->wps_ie_len); + + memcpy(buf, bss->wps_ie, bss->wps_ie_len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = bss_desc->wps_ie_len; + start = iwe_stream_add_point(info, start, stop, &iwe, buf); + } + } + if (bss_desc->wapi_ie_len) { + char buf[200]; + unsigned char pos = 0; + + memset(&iwe, 0, sizeof(iwe)); + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "translate_scan, wapi_len %d\n", + bss_desc->wapi_ie_len); + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "%02x %02x %02x %02x ... ... %02x %02x %02x %02x\n", + bss_desc->wapi_ie[0], bss_desc->wapi_ie[1], + bss_desc->wapi_ie[2], bss_desc->wapi_ie[3], + bss_desc->wapi_ie[bss_desc->wapi_ie_len - 4], + bss_desc->wapi_ie[bss_desc->wapi_ie_len - 3], + bss_desc->wapi_ie[bss_desc->wapi_ie_len - 2], + bss_desc->wapi_ie[bss_desc->wapi_ie_len - 1]); + + memcpy(buf, "wapi_ie=", 8); + + while (pos < bss_desc->wapi_ie_len) { + //transfer hex to ascii string because wpa_supplicant need do so + num_2_str(bss_desc->wapi_ie[pos], + (unsigned char *)(buf + 8 + 2 * pos)); + pos++; + } + + iwe.cmd = IWEVCUSTOM; + iwe.u.data.length = bss_desc->wapi_ie_len * 2 + 8; + start = iwe_stream_add_point(info, start, stop, &iwe, buf); + } + + return start; +} + +/** + * @brief Handle Scan Network ioctl + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +int wlan_set_scan(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s scan:%d assoc:%d <<< \n", + __func__, priv->scan_running, priv->assoc_ongoing); + + if (!is_sdio_init_complete() || priv->scan_running == WLAN_SCAN_RUNNING + || priv->assoc_ongoing || priv->sdio_need_reset) + goto out; + + if (wrqu->data.length == sizeof(struct iw_scan_req) && + wrqu->data.flags & IW_SCAN_THIS_ESSID) { + struct iw_scan_req *req = (struct iw_scan_req *)extra; + priv->scan_ssid_len = req->essid_len > 32 ? 32 : req->essid_len; + memcpy(priv->scan_ssid, req->essid, priv->scan_ssid_len); + priv->scan_ssid[priv->scan_ssid_len] = '\0'; + } else { + priv->scan_ssid_len = 0; + memset(priv->scan_ssid, '\0', sizeof(priv->scan_ssid)); + } + + wlan_set_rssi_dirty(priv); + priv->scan_running = WLAN_SCAN_RUNNING; + ret = wlan_start_scan_enable_network_info(priv); + if (!ret) { + wlan_mod_timer(&priv->ScanResultsTimeout, 1500); + } else { + priv->scan_running = WLAN_SCAN_IDLE; + } +out: + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s ret %d >>> \n", __func__, ret); + return 0; +} + + +void wlan_set_scan_by_driver(wlan_private *priv) +{ + int ret = 0; + priv->scan_ssid_len = 0; + memset(priv->scan_ssid, '\0', sizeof(priv->scan_ssid)); + priv->scan_running = WLAN_SCAN_RUNNING; + ret = wlan_start_scan_enable_network_info(priv); + if (!ret) { + wlan_mod_timer(&priv->ScanResultsTimeout, 1500); + } else { + priv->scan_running = WLAN_SCAN_IDLE; + } +} + + +static inline unsigned int elapsed_jiffies_msecs(unsigned long start) +{ + unsigned long end = jiffies; + + if (end >= start) + return jiffies_to_msecs(end - start); + + return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1); +} + +/** + * @brief Handle Retrieve scan table ioctl + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +int wlan_get_scan(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ +#define SCAN_ITEM_SIZE 128 + wlan_private *priv = (wlan_private *) netdev_priv(dev); + int ret = 0; + struct bss_descriptor *iter_bss; + struct bss_descriptor *safe; + char *ev = extra; + char *stop = ev + dwrq->length; + u8 items = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_DEBUG, "%s >>>\n", __func__); + + /* iwlist should wait until the current scan is finished */ + if (priv->scan_running == WLAN_SCAN_RUNNING) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "Scan is Running, return AGAIN\n"); + return -EAGAIN; + } + + spin_lock(&priv->ScanListLock); + /* report all bss to upper layer */ + list_for_each_entry_safe(iter_bss, safe, &priv->network_list, list) { + char *next_ev; + unsigned long stale_time; + + + if (stop - ev < SCAN_ITEM_SIZE) { + ret = -E2BIG; + break; + } + + if (!iter_bss->ssid_len){ + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE,"No valid AP here\n"); + continue; + } + + /* Prune old an old scan result */ + stale_time = iter_bss->last_scanned + DEFAULT_MAX_SCAN_AGE; + if (time_before(stale_time, jiffies)) { + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "Not show %s, due to age (%ums).\n", iter_bss->ssid, + elapsed_jiffies_msecs(iter_bss->last_scanned)); + clear_bss_descriptor(iter_bss); + continue; + } + +#ifdef WIFI_SELECT_CHANNEL + if (iter_bss->channel > channel_nums) { + clear_bss_descriptor(iter_bss); + continue; + } +#endif + /* Translate to WE format this entry */ + next_ev = translate_scan(priv, info, ev, stop, iter_bss); + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "Report BSS %s\n", iter_bss->ssid); + + if (next_ev == NULL) + continue; + ev = next_ev; + items++; + } + spin_unlock(&priv->ScanListLock); + dwrq->length = (ev - extra); + dwrq->flags = 0; + + if (priv->scan_running != WLAN_SCAN_RUNNING) + priv->scan_running = WLAN_SCAN_IDLE; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s ap:%d< <<\n", __func__, items); + return ret; +} + +int wlan_set_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct iw_mlme *mlme = (struct iw_mlme *)extra; + wlan_private *priv = netdev_priv(dev); + int ret = 0; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + case IW_MLME_DISASSOC: + { + unsigned char null_data[6]; + memset(null_data, 0, 6); + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "DISASSOC\n"); + + wlan_cancel_timer(&priv->AssociationTimeOut); + wlan_cancel_timer(&priv->ReAssociationTimeOut); + priv->assoc_ongoing = FALSE; + + /* silently ignore */ + if(priv->version >= WLAN_VERSION_91){ + //wlan_set_bssid(priv, null_data); + //wlan_disconnect(priv); + ret = wlan_disconnect_silent(priv); + } + else + ret = wlan_set_ssid((wlan_private *) netdev_priv(dev), null_data, 6); + + } + break; + default: + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, + "Not supported cmd %d\n", mlme->cmd); + ret = -EOPNOTSUPP; + break; + } + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s <<<\n", __func__); + return ret; +} + +#define MAX_WX_STRING 80 +static int wl_iw_get_macaddr(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int error; + char *p = extra; + char buf[ETH_ALEN] = { 0 }; + wlan_private *priv = netdev_priv(dev); + + error = wlan_get_mac_addr(priv, buf); + p += snprintf(p, MAX_WX_STRING, + "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", buf[0], + buf[1], buf[2], buf[3], buf[4], buf[5]); + + wrqu->data.length = p - extra + 1; + + return error; +} + +static int wlan_set_priv(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *ext) +{ + int ret = 0; + char *extra; + + if (!(extra = kmalloc(dwrq->length, GFP_KERNEL))) + return -ENOMEM; + + if (copy_from_user(extra, dwrq->pointer, dwrq->length)) { + kfree(extra); + return -EFAULT; + } + + if (dwrq->length && extra) { + if (strnicmp(extra, "MACADDR", strlen("MACADDR")) == 0) { + ret = + wl_iw_get_macaddr(dev, info, + (union iwreq_data *)dwrq, extra); + } else if (strnicmp(extra, "CSCAN", strlen("CSCAN")) == 0) { + } + } + + if (extra) { + if (copy_to_user(dwrq->pointer, extra, dwrq->length)) { + kfree(extra); + return -EFAULT; + } + kfree(extra); + } + + return ret; +} + +static int wlan_wext_get_wireless_stats(struct net_device *dev, + struct iw_request_info *info, + u32 * uwrq, char *extra) +{ + struct iw_statistics *wstats = (struct iw_statistics *)extra; + wlan_private *priv = netdev_priv(dev); + int ret = 0; + int stats_valid = 0; + u8 snr; + + WLAN_DBGLAP(WLAN_DA_WEXT, WLAN_DL_TRACE, "%s >>>\n", __func__); + + ret = wlan_update_bss_stats(priv); + if (ret) + goto out; + + wstats->miss.beacon = 0; + wstats->discard.retries = 0; + wstats->qual.level = 0x100 + (s8)priv->curbssparams.rssi; + + snr = wstats->qual.level - WLAN_NF_DEFAULT_SCAN_VALUE; + wstats->qual.qual = + (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - snr) * + (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - snr))) / + (RSSI_DIFF * RSSI_DIFF); + if (wstats->qual.qual > 100) + wstats->qual.qual = 100; + wstats->qual.noise = WLAN_NF_DEFAULT_SCAN_VALUE; + wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; + + stats_valid = 1; + +out: + if (!stats_valid) { + wstats->miss.beacon = 0; + wstats->discard.retries = 0; + wstats->qual.qual = 0; + wstats->qual.level = 0; + wstats->qual.noise = 0; + wstats->qual.updated = IW_QUAL_ALL_UPDATED; + wstats->qual.updated |= IW_QUAL_NOISE_INVALID | + IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; + } + return ret; +} + +/* + * iwconfig settable callbacks + */ +static const iw_handler wlan_wext_handler[] = { + (iw_handler) NULL, /* SIOCSIWCOMMIT */ + (iw_handler) wlan_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */ + (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */ + (iw_handler) wlan_set_mode, /* SIOCSIWMODE */ + (iw_handler) wlan_get_mode, /* SIOCGIWMODE */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) wlan_get_range, /* SIOCGIWRANGE */ + (iw_handler) wlan_set_priv, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) wlan_wext_get_wireless_stats, /* SIOCGIWSTATS */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ + (iw_handler) NULL, /* SIOCSIWTHRSPY */ + (iw_handler) NULL, /* SIOCGIWTHRSPY */ + (iw_handler) wlan_set_wap, /* SIOCSIWAP */ + (iw_handler) wlan_get_wap, /* SIOCGIWAP */ + (iw_handler) wlan_set_mlme, /* SIOCSIWMLME */ + (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */ + (iw_handler) wlan_set_scan, /* SIOCSIWSCAN */ + (iw_handler) wlan_get_scan, /* SIOCGIWSCAN */ + (iw_handler) wlan_set_essid, /* SIOCSIWESSID */ + (iw_handler) wlan_get_essid, /* SIOCGIWESSID */ + (iw_handler) wlan_set_nick, /* SIOCSIWNICKN */ + (iw_handler) wlan_get_nick, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) wlan_set_rate, /* SIOCSIWRATE */ + (iw_handler) wlan_get_rate, /* SIOCGIWRATE */ + (iw_handler) wlan_set_rts, /* SIOCSIWRTS */ + (iw_handler) wlan_get_rts, /* SIOCGIWRTS */ + (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */ + (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */ + (iw_handler) wlan_set_txpow, /* SIOCSIWTXPOW */ + (iw_handler) wlan_get_txpow, /* SIOCGIWTXPOW */ + (iw_handler) wlan_set_retry, /* SIOCSIWRETRY */ + (iw_handler) wlan_get_retry, /* SIOCGIWRETRY */ + (iw_handler) wlan_set_encode, /* SIOCSIWENCODE */ + (iw_handler) wlan_get_encode, /* SIOCGIWENCODE */ + (iw_handler) wlan_set_power, /* SIOCSIWPOWER */ + (iw_handler) wlan_get_power, /* SIOCGIWPOWER */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) wlan_set_genie, /* SIOCSIWGENIE */ + (iw_handler) wlan_get_genie, /* SIOCGIWGENIE */ + (iw_handler) wlan_set_auth, /* SIOCSIWAUTH */ + (iw_handler) wlan_get_auth, /* SIOCGIWAUTH */ + (iw_handler) wlan_set_encodeext, /* SIOCSIWENCODEEXT */ + (iw_handler) wlan_get_encodeext, /* SIOCGIWENCODEEXT */ + (iw_handler) wlan_set_pmksa, /* SIOCSIWPMKSA */ +}; + +struct iw_handler_def wlan_wext_handler_def = { + .num_standard = ARRAY_SIZE(wlan_wext_handler), + .standard = (iw_handler *) wlan_wext_handler, + .get_wireless_stats = wlan_get_wireless_stats, +}; |