diff options
Diffstat (limited to 'drivers/net/wireless/iwmc3200wifi/wext.c')
-rw-r--r-- | drivers/net/wireless/iwmc3200wifi/wext.c | 723 |
1 files changed, 723 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwmc3200wifi/wext.c b/drivers/net/wireless/iwmc3200wifi/wext.c new file mode 100644 index 000000000000..584c94d0f399 --- /dev/null +++ b/drivers/net/wireless/iwmc3200wifi/wext.c @@ -0,0 +1,723 @@ +/* + * Intel Wireless Multicomm 3200 WiFi driver + * + * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> + * Samuel Ortiz <samuel.ortiz@intel.com> + * Zhu Yi <yi.zhu@intel.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + */ + +#include <linux/kernel.h> +#include <linux/netdevice.h> +#include <linux/wireless.h> +#include <linux/if_arp.h> +#include <linux/etherdevice.h> +#include <net/cfg80211.h> +#include <net/iw_handler.h> + +#include "iwm.h" +#include "umac.h" +#include "commands.h" +#include "debug.h" + +static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + struct iw_statistics *wstats = &iwm->wstats; + + if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { + memset(wstats, 0, sizeof(struct iw_statistics)); + wstats->qual.updated = IW_QUAL_ALL_INVALID; + } + + return wstats; +} + +static int iwm_wext_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + if (freq->flags == IW_FREQ_AUTO) + return 0; + + /* frequency/channel can only be set in IBSS mode */ + if (iwm->conf.mode != UMAC_MODE_IBSS) + return -EOPNOTSUPP; + + return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra); +} + +static int iwm_wext_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + if (iwm->conf.mode == UMAC_MODE_IBSS) + return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); + + freq->e = 0; + freq->m = iwm->channel; + + return 0; +} + +static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + if (iwm->conf.mode == UMAC_MODE_IBSS) + return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra); + + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return -EIO; + + if (is_zero_ether_addr(ap_addr->sa_data) || + is_broadcast_ether_addr(ap_addr->sa_data)) { + IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n", + iwm->umac_profile->bssid[0]); + memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN); + iwm->umac_profile->bss_num = 0; + } else { + IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n", + ap_addr->sa_data); + memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data, + ETH_ALEN); + iwm->umac_profile->bss_num = 1; + } + + if (iwm->umac_profile_active) { + if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN)) + return 0; + + iwm_invalidate_mlme_profile(iwm); + } + + if (iwm->umac_profile->ssid.ssid_len) + return iwm_send_mlme_profile(iwm); + + return 0; +} + +static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + switch (iwm->conf.mode) { + case UMAC_MODE_IBSS: + return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra); + case UMAC_MODE_BSS: + if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { + ap_addr->sa_family = ARPHRD_ETHER; + memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN); + } else + memset(&ap_addr->sa_data, 0, ETH_ALEN); + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int iwm_wext_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + size_t len = data->length; + int ret; + + if (iwm->conf.mode == UMAC_MODE_IBSS) + return cfg80211_ibss_wext_siwessid(dev, info, data, ssid); + + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return -EIO; + + if (len > 0 && ssid[len - 1] == '\0') + len--; + + if (iwm->umac_profile_active) { + if (iwm->umac_profile->ssid.ssid_len == len && + !memcmp(iwm->umac_profile->ssid.ssid, ssid, len)) + return 0; + + ret = iwm_invalidate_mlme_profile(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't invalidate profile\n"); + return ret; + } + } + + iwm->umac_profile->ssid.ssid_len = len; + memcpy(iwm->umac_profile->ssid.ssid, ssid, len); + + return iwm_send_mlme_profile(iwm); +} + +static int iwm_wext_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + if (iwm->conf.mode == UMAC_MODE_IBSS) + return cfg80211_ibss_wext_giwessid(dev, info, data, ssid); + + if (!test_bit(IWM_STATUS_READY, &iwm->status)) + return -EIO; + + data->length = iwm->umac_profile->ssid.ssid_len; + if (data->length) { + memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length); + data->flags = 1; + } else + data->flags = 0; + + return 0; +} + +static struct iwm_key * +iwm_key_init(struct iwm_priv *iwm, u8 key_idx, bool in_use, + struct iw_encode_ext *ext, u8 alg) +{ + struct iwm_key *key = &iwm->keys[key_idx]; + + memset(key, 0, sizeof(struct iwm_key)); + memcpy(key->hdr.mac, ext->addr.sa_data, ETH_ALEN); + key->hdr.key_idx = key_idx; + if (is_broadcast_ether_addr(ext->addr.sa_data)) + key->hdr.multicast = 1; + + key->in_use = in_use; + key->flags = ext->ext_flags; + key->alg = alg; + key->key_len = ext->key_len; + memcpy(key->key, ext->key, ext->key_len); + + return key; +} + +static int iwm_wext_giwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rate, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + rate->value = iwm->rate * 1000000; + + return 0; +} + +static int iwm_wext_siwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *key_buf) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + struct iwm_key *uninitialized_var(key); + int idx, i, uninitialized_var(alg), remove = 0, ret; + + IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", erq->length); + IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags); + + if (!iwm->umac_profile) { + IWM_ERR(iwm, "UMAC profile not allocated yet\n"); + return -ENODEV; + } + + if (erq->length == WLAN_KEY_LEN_WEP40) { + alg = UMAC_CIPHER_TYPE_WEP_40; + iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_40; + iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_40; + } else if (erq->length == WLAN_KEY_LEN_WEP104) { + alg = UMAC_CIPHER_TYPE_WEP_104; + iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_104; + iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_104; + } + + if (erq->flags & IW_ENCODE_RESTRICTED) + iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; + else + iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN; + + idx = erq->flags & IW_ENCODE_INDEX; + if (idx == 0) { + if (iwm->default_key) + for (i = 0; i < IWM_NUM_KEYS; i++) { + if (iwm->default_key == &iwm->keys[i]) { + idx = i; + break; + } + } + else + iwm->default_key = &iwm->keys[idx]; + } else if (idx < 1 || idx > 4) { + return -EINVAL; + } else + idx--; + + if (erq->flags & IW_ENCODE_DISABLED) + remove = 1; + else if (erq->length == 0) { + if (!iwm->keys[idx].in_use) + return -EINVAL; + iwm->default_key = &iwm->keys[idx]; + } + + if (erq->length) { + key = &iwm->keys[idx]; + memset(key, 0, sizeof(struct iwm_key)); + memset(key->hdr.mac, 0xff, ETH_ALEN); + key->hdr.key_idx = idx; + key->hdr.multicast = 1; + key->in_use = !remove; + key->alg = alg; + key->key_len = erq->length; + memcpy(key->key, key_buf, erq->length); + + IWM_DBG_WEXT(iwm, DBG, "Setting key %d, default: %d\n", + idx, !!iwm->default_key); + } + + if (remove) { + if ((erq->flags & IW_ENCODE_NOKEY) || (erq->length == 0)) { + int j; + for (j = 0; j < IWM_NUM_KEYS; j++) + if (iwm->keys[j].in_use) { + struct iwm_key *k = &iwm->keys[j]; + + k->in_use = 0; + ret = iwm_set_key(iwm, remove, 0, k); + if (ret < 0) + return ret; + } + + iwm->umac_profile->sec.ucast_cipher = + UMAC_CIPHER_TYPE_NONE; + iwm->umac_profile->sec.mcast_cipher = + UMAC_CIPHER_TYPE_NONE; + iwm->umac_profile->sec.auth_type = + UMAC_AUTH_TYPE_OPEN; + + return 0; + } else { + key->in_use = 0; + return iwm_set_key(iwm, remove, 0, key); + } + } + + /* + * If we havent set a profile yet, we cant set keys. + * Keys will be pushed after we're associated. + */ + if (!iwm->umac_profile_active) + return 0; + + /* + * If there is a current active profile, but no + * default key, it's not worth trying to associate again. + */ + if (!iwm->default_key) + return 0; + + /* + * Here we have an active profile, but a key setting changed. + * We thus have to invalidate the current profile, and push the + * new one. Keys will be pushed when association takes place. + */ + ret = iwm_invalidate_mlme_profile(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't invalidate profile\n"); + return ret; + } + + return iwm_send_mlme_profile(iwm); +} + +static int iwm_wext_giwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *key) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + int idx, i; + + idx = erq->flags & IW_ENCODE_INDEX; + if (idx < 1 || idx > 4) { + idx = -1; + if (!iwm->default_key) { + erq->length = 0; + erq->flags |= IW_ENCODE_NOKEY; + return 0; + } else + for (i = 0; i < IWM_NUM_KEYS; i++) { + if (iwm->default_key == &iwm->keys[i]) { + idx = i; + break; + } + } + if (idx < 0) + return -EINVAL; + } else + idx--; + + erq->flags = idx + 1; + + if (!iwm->keys[idx].in_use) { + erq->length = 0; + erq->flags |= IW_ENCODE_DISABLED; + return 0; + } + + memcpy(key, iwm->keys[idx].key, + min_t(int, erq->length, iwm->keys[idx].key_len)); + erq->length = iwm->keys[idx].key_len; + erq->flags |= IW_ENCODE_ENABLED; + + if (iwm->umac_profile->mode == UMAC_MODE_BSS) { + switch (iwm->umac_profile->sec.auth_type) { + case UMAC_AUTH_TYPE_OPEN: + erq->flags |= IW_ENCODE_OPEN; + break; + default: + erq->flags |= IW_ENCODE_RESTRICTED; + break; + } + } + + return 0; +} + +static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version) +{ + if (wpa_version & IW_AUTH_WPA_VERSION_WPA2) + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK; + else if (wpa_version & IW_AUTH_WPA_VERSION_WPA) + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK; + else + iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE; + + return 0; +} + +static int iwm_wext_siwpower(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *wrq, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + u32 power_index; + + if (wrq->disabled) { + power_index = IWM_POWER_INDEX_MIN; + goto set; + } else + power_index = IWM_POWER_INDEX_DEFAULT; + + switch (wrq->flags & IW_POWER_MODE) { + case IW_POWER_ON: + case IW_POWER_MODE: + case IW_POWER_ALL_R: + break; + default: + return -EINVAL; + } + + set: + if (power_index == iwm->conf.power_index) + return 0; + + iwm->conf.power_index = power_index; + + return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, + CFG_POWER_INDEX, iwm->conf.power_index); +} + +static int iwm_wext_giwpower(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + + wrqu->power.disabled = (iwm->conf.power_index == IWM_POWER_INDEX_MIN); + + return 0; +} + +static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt) +{ + u8 *auth_type = &iwm->umac_profile->sec.auth_type; + + if (key_mgt == IW_AUTH_KEY_MGMT_802_1X) + *auth_type = UMAC_AUTH_TYPE_8021X; + else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) { + if (iwm->umac_profile->sec.flags & + (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) + *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; + else + *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; + } else { + IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt); + return -EINVAL; + } + + return 0; +} + +static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast) +{ + u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher : + &iwm->umac_profile->sec.mcast_cipher; + + switch (cipher) { + case IW_AUTH_CIPHER_NONE: + *profile_cipher = UMAC_CIPHER_TYPE_NONE; + break; + case IW_AUTH_CIPHER_WEP40: + *profile_cipher = UMAC_CIPHER_TYPE_WEP_40; + break; + case IW_AUTH_CIPHER_TKIP: + *profile_cipher = UMAC_CIPHER_TYPE_TKIP; + break; + case IW_AUTH_CIPHER_CCMP: + *profile_cipher = UMAC_CIPHER_TYPE_CCMP; + break; + case IW_AUTH_CIPHER_WEP104: + *profile_cipher = UMAC_CIPHER_TYPE_WEP_104; + break; + default: + IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher); + return -ENOTSUPP; + } + + return 0; +} + +static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg) +{ + u8 *auth_type = &iwm->umac_profile->sec.auth_type; + + switch (auth_alg) { + case IW_AUTH_ALG_OPEN_SYSTEM: + *auth_type = UMAC_AUTH_TYPE_OPEN; + break; + case IW_AUTH_ALG_SHARED_KEY: + if (iwm->umac_profile->sec.flags & + (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) { + if (*auth_type == UMAC_AUTH_TYPE_8021X) + return -EINVAL; + *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; + } else { + *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; + } + break; + case IW_AUTH_ALG_LEAP: + default: + IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg); + return -ENOTSUPP; + } + + return 0; +} + +static int iwm_wext_siwauth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *data, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + int ret; + + if ((data->flags) & + (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT | + IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) { + /* We need to invalidate the current profile */ + if (iwm->umac_profile_active) { + ret = iwm_invalidate_mlme_profile(iwm); + if (ret < 0) { + IWM_ERR(iwm, "Couldn't invalidate profile\n"); + return ret; + } + } + } + + switch (data->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + return iwm_set_wpa_version(iwm, data->value); + break; + case IW_AUTH_CIPHER_PAIRWISE: + return iwm_set_cipher(iwm, data->value, 1); + break; + case IW_AUTH_CIPHER_GROUP: + return iwm_set_cipher(iwm, data->value, 0); + break; + case IW_AUTH_KEY_MGMT: + return iwm_set_key_mgt(iwm, data->value); + break; + case IW_AUTH_80211_AUTH_ALG: + return iwm_set_auth_alg(iwm, data->value); + break; + default: + return -ENOTSUPP; + } + + return 0; +} + +static int iwm_wext_giwauth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *data, char *extra) +{ + return 0; +} + +static int iwm_wext_siwencodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *extra) +{ + struct iwm_priv *iwm = ndev_to_iwm(dev); + struct iwm_key *key; + struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; + int uninitialized_var(alg), idx, i, remove = 0; + + IWM_DBG_WEXT(iwm, DBG, "alg: 0x%x\n", ext->alg); + IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", ext->key_len); + IWM_DBG_WEXT(iwm, DBG, "ext_flags: 0x%x\n", ext->ext_flags); + IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags); + IWM_DBG_WEXT(iwm, DBG, "length: 0x%x\n", erq->length); + + switch (ext->alg) { + case IW_ENCODE_ALG_NONE: + remove = 1; + break; + case IW_ENCODE_ALG_WEP: + if (ext->key_len == WLAN_KEY_LEN_WEP40) + alg = UMAC_CIPHER_TYPE_WEP_40; + else if (ext->key_len == WLAN_KEY_LEN_WEP104) + alg = UMAC_CIPHER_TYPE_WEP_104; + else { + IWM_ERR(iwm, "Invalid key length: %d\n", ext->key_len); + return -EINVAL; + } + + break; + case IW_ENCODE_ALG_TKIP: + alg = UMAC_CIPHER_TYPE_TKIP; + break; + case IW_ENCODE_ALG_CCMP: + alg = UMAC_CIPHER_TYPE_CCMP; + break; + default: + return -EOPNOTSUPP; + } + + idx = erq->flags & IW_ENCODE_INDEX; + + if (idx == 0) { + if (iwm->default_key) + for (i = 0; i < IWM_NUM_KEYS; i++) { + if (iwm->default_key == &iwm->keys[i]) { + idx = i; + break; + } + } + } else if (idx < 1 || idx > 4) { + return -EINVAL; + } else + idx--; + + if (erq->flags & IW_ENCODE_DISABLED) + remove = 1; + else if ((erq->length == 0) || + (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) { + iwm->default_key = &iwm->keys[idx]; + if (iwm->umac_profile_active && ext->alg == IW_ENCODE_ALG_WEP) + return iwm_set_tx_key(iwm, idx); + } + + key = iwm_key_init(iwm, idx, !remove, ext, alg); + + return iwm_set_key(iwm, remove, !iwm->default_key, key); +} + +static const iw_handler iwm_handlers[] = +{ + (iw_handler) NULL, /* SIOCSIWCOMMIT */ + (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) iwm_wext_siwfreq, /* SIOCSIWFREQ */ + (iw_handler) iwm_wext_giwfreq, /* SIOCGIWFREQ */ + (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */ + (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ + (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ + (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */ + (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ + (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ + (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ + (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ + (iw_handler) NULL, /* SIOCSIWTHRSPY */ + (iw_handler) NULL, /* SIOCGIWTHRSPY */ + (iw_handler) iwm_wext_siwap, /* SIOCSIWAP */ + (iw_handler) iwm_wext_giwap, /* SIOCGIWAP */ + (iw_handler) NULL, /* SIOCSIWMLME */ + (iw_handler) NULL, /* SIOCGIWAPLIST */ + (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */ + (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */ + (iw_handler) iwm_wext_siwessid, /* SIOCSIWESSID */ + (iw_handler) iwm_wext_giwessid, /* SIOCGIWESSID */ + (iw_handler) NULL, /* SIOCSIWNICKN */ + (iw_handler) NULL, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCSIWRATE */ + (iw_handler) iwm_wext_giwrate, /* SIOCGIWRATE */ + (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */ + (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */ + (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */ + (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */ + (iw_handler) NULL, /* SIOCSIWTXPOW */ + (iw_handler) NULL, /* SIOCGIWTXPOW */ + (iw_handler) NULL, /* SIOCSIWRETRY */ + (iw_handler) NULL, /* SIOCGIWRETRY */ + (iw_handler) iwm_wext_siwencode, /* SIOCSIWENCODE */ + (iw_handler) iwm_wext_giwencode, /* SIOCGIWENCODE */ + (iw_handler) iwm_wext_siwpower, /* SIOCSIWPOWER */ + (iw_handler) iwm_wext_giwpower, /* SIOCGIWPOWER */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCSIWGENIE */ + (iw_handler) NULL, /* SIOCGIWGENIE */ + (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */ + (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */ + (iw_handler) iwm_wext_siwencodeext, /* SIOCSIWENCODEEXT */ + (iw_handler) NULL, /* SIOCGIWENCODEEXT */ + (iw_handler) NULL, /* SIOCSIWPMKSA */ + (iw_handler) NULL, /* -- hole -- */ +}; + +const struct iw_handler_def iwm_iw_handler_def = { + .num_standard = ARRAY_SIZE(iwm_handlers), + .standard = (iw_handler *) iwm_handlers, + .get_wireless_stats = iwm_get_wireless_stats, +}; + |