2 * Intel Wireless Multicomm 3200 WiFi driver
4 * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
5 * Samuel Ortiz <samuel.ortiz@intel.com>
6 * Zhu Yi <yi.zhu@intel.com>
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 #include <linux/kernel.h>
25 #include <linux/netdevice.h>
26 #include <linux/wireless.h>
27 #include <linux/if_arp.h>
28 #include <linux/etherdevice.h>
29 #include <net/cfg80211.h>
30 #include <net/iw_handler.h>
37 static struct iw_statistics *iwm_get_wireless_stats(struct net_device *dev)
39 struct iwm_priv *iwm = ndev_to_iwm(dev);
40 struct iw_statistics *wstats = &iwm->wstats;
42 if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
43 memset(wstats, 0, sizeof(struct iw_statistics));
44 wstats->qual.updated = IW_QUAL_ALL_INVALID;
50 static int iwm_wext_siwfreq(struct net_device *dev,
51 struct iw_request_info *info,
52 struct iw_freq *freq, char *extra)
54 struct iwm_priv *iwm = ndev_to_iwm(dev);
56 if (freq->flags == IW_FREQ_AUTO)
59 /* frequency/channel can only be set in IBSS mode */
60 if (iwm->conf.mode != UMAC_MODE_IBSS)
63 return cfg80211_ibss_wext_siwfreq(dev, info, freq, extra);
66 static int iwm_wext_giwfreq(struct net_device *dev,
67 struct iw_request_info *info,
68 struct iw_freq *freq, char *extra)
70 struct iwm_priv *iwm = ndev_to_iwm(dev);
72 if (iwm->conf.mode == UMAC_MODE_IBSS)
73 return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
76 freq->m = iwm->channel;
81 static int iwm_wext_siwap(struct net_device *dev, struct iw_request_info *info,
82 struct sockaddr *ap_addr, char *extra)
84 struct iwm_priv *iwm = ndev_to_iwm(dev);
86 if (iwm->conf.mode == UMAC_MODE_IBSS)
87 return cfg80211_ibss_wext_siwap(dev, info, ap_addr, extra);
89 if (!test_bit(IWM_STATUS_READY, &iwm->status))
92 if (is_zero_ether_addr(ap_addr->sa_data) ||
93 is_broadcast_ether_addr(ap_addr->sa_data)) {
94 IWM_DBG_WEXT(iwm, DBG, "clear mandatory bssid %pM\n",
95 iwm->umac_profile->bssid[0]);
96 memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN);
97 iwm->umac_profile->bss_num = 0;
99 IWM_DBG_WEXT(iwm, DBG, "add mandatory bssid %pM\n",
101 memcpy(&iwm->umac_profile->bssid[0], ap_addr->sa_data,
103 iwm->umac_profile->bss_num = 1;
106 if (iwm->umac_profile_active) {
107 if (!memcmp(&iwm->umac_profile->bssid[0], iwm->bssid, ETH_ALEN))
110 iwm_invalidate_mlme_profile(iwm);
113 if (iwm->umac_profile->ssid.ssid_len)
114 return iwm_send_mlme_profile(iwm);
119 static int iwm_wext_giwap(struct net_device *dev, struct iw_request_info *info,
120 struct sockaddr *ap_addr, char *extra)
122 struct iwm_priv *iwm = ndev_to_iwm(dev);
124 switch (iwm->conf.mode) {
126 return cfg80211_ibss_wext_giwap(dev, info, ap_addr, extra);
128 if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) {
129 ap_addr->sa_family = ARPHRD_ETHER;
130 memcpy(&ap_addr->sa_data, iwm->bssid, ETH_ALEN);
132 memset(&ap_addr->sa_data, 0, ETH_ALEN);
141 static int iwm_wext_siwessid(struct net_device *dev,
142 struct iw_request_info *info,
143 struct iw_point *data, char *ssid)
145 struct iwm_priv *iwm = ndev_to_iwm(dev);
146 size_t len = data->length;
149 if (iwm->conf.mode == UMAC_MODE_IBSS)
150 return cfg80211_ibss_wext_siwessid(dev, info, data, ssid);
152 if (!test_bit(IWM_STATUS_READY, &iwm->status))
155 if (len > 0 && ssid[len - 1] == '\0')
158 if (iwm->umac_profile_active) {
159 if (iwm->umac_profile->ssid.ssid_len == len &&
160 !memcmp(iwm->umac_profile->ssid.ssid, ssid, len))
163 ret = iwm_invalidate_mlme_profile(iwm);
165 IWM_ERR(iwm, "Couldn't invalidate profile\n");
170 iwm->umac_profile->ssid.ssid_len = len;
171 memcpy(iwm->umac_profile->ssid.ssid, ssid, len);
173 return iwm_send_mlme_profile(iwm);
176 static int iwm_wext_giwessid(struct net_device *dev,
177 struct iw_request_info *info,
178 struct iw_point *data, char *ssid)
180 struct iwm_priv *iwm = ndev_to_iwm(dev);
182 if (iwm->conf.mode == UMAC_MODE_IBSS)
183 return cfg80211_ibss_wext_giwessid(dev, info, data, ssid);
185 if (!test_bit(IWM_STATUS_READY, &iwm->status))
188 data->length = iwm->umac_profile->ssid.ssid_len;
190 memcpy(ssid, iwm->umac_profile->ssid.ssid, data->length);
198 static struct iwm_key *
199 iwm_key_init(struct iwm_priv *iwm, u8 key_idx, bool in_use,
200 struct iw_encode_ext *ext, u8 alg)
202 struct iwm_key *key = &iwm->keys[key_idx];
204 memset(key, 0, sizeof(struct iwm_key));
205 memcpy(key->hdr.mac, ext->addr.sa_data, ETH_ALEN);
206 key->hdr.key_idx = key_idx;
207 if (is_broadcast_ether_addr(ext->addr.sa_data))
208 key->hdr.multicast = 1;
210 key->in_use = in_use;
211 key->flags = ext->ext_flags;
213 key->key_len = ext->key_len;
214 memcpy(key->key, ext->key, ext->key_len);
219 static int iwm_wext_giwrate(struct net_device *dev,
220 struct iw_request_info *info,
221 struct iw_param *rate, char *extra)
223 struct iwm_priv *iwm = ndev_to_iwm(dev);
225 rate->value = iwm->rate * 1000000;
230 static int iwm_wext_siwencode(struct net_device *dev,
231 struct iw_request_info *info,
232 struct iw_point *erq, char *key_buf)
234 struct iwm_priv *iwm = ndev_to_iwm(dev);
235 struct iwm_key *uninitialized_var(key);
236 int idx, i, uninitialized_var(alg), remove = 0, ret;
238 IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", erq->length);
239 IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
241 if (!iwm->umac_profile) {
242 IWM_ERR(iwm, "UMAC profile not allocated yet\n");
246 if (erq->length == WLAN_KEY_LEN_WEP40) {
247 alg = UMAC_CIPHER_TYPE_WEP_40;
248 iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_40;
249 iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
250 } else if (erq->length == WLAN_KEY_LEN_WEP104) {
251 alg = UMAC_CIPHER_TYPE_WEP_104;
252 iwm->umac_profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_WEP_104;
253 iwm->umac_profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_WEP_104;
256 if (erq->flags & IW_ENCODE_RESTRICTED)
257 iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
259 iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN;
261 idx = erq->flags & IW_ENCODE_INDEX;
263 if (iwm->default_key)
264 for (i = 0; i < IWM_NUM_KEYS; i++) {
265 if (iwm->default_key == &iwm->keys[i]) {
271 iwm->default_key = &iwm->keys[idx];
272 } else if (idx < 1 || idx > 4) {
277 if (erq->flags & IW_ENCODE_DISABLED)
279 else if (erq->length == 0) {
280 if (!iwm->keys[idx].in_use)
282 iwm->default_key = &iwm->keys[idx];
286 key = &iwm->keys[idx];
287 memset(key, 0, sizeof(struct iwm_key));
288 memset(key->hdr.mac, 0xff, ETH_ALEN);
289 key->hdr.key_idx = idx;
290 key->hdr.multicast = 1;
291 key->in_use = !remove;
293 key->key_len = erq->length;
294 memcpy(key->key, key_buf, erq->length);
296 IWM_DBG_WEXT(iwm, DBG, "Setting key %d, default: %d\n",
297 idx, !!iwm->default_key);
301 if ((erq->flags & IW_ENCODE_NOKEY) || (erq->length == 0)) {
303 for (j = 0; j < IWM_NUM_KEYS; j++)
304 if (iwm->keys[j].in_use) {
305 struct iwm_key *k = &iwm->keys[j];
308 ret = iwm_set_key(iwm, remove, 0, k);
313 iwm->umac_profile->sec.ucast_cipher =
314 UMAC_CIPHER_TYPE_NONE;
315 iwm->umac_profile->sec.mcast_cipher =
316 UMAC_CIPHER_TYPE_NONE;
317 iwm->umac_profile->sec.auth_type =
323 return iwm_set_key(iwm, remove, 0, key);
328 * If we havent set a profile yet, we cant set keys.
329 * Keys will be pushed after we're associated.
331 if (!iwm->umac_profile_active)
335 * If there is a current active profile, but no
336 * default key, it's not worth trying to associate again.
338 if (!iwm->default_key)
342 * Here we have an active profile, but a key setting changed.
343 * We thus have to invalidate the current profile, and push the
344 * new one. Keys will be pushed when association takes place.
346 ret = iwm_invalidate_mlme_profile(iwm);
348 IWM_ERR(iwm, "Couldn't invalidate profile\n");
352 return iwm_send_mlme_profile(iwm);
355 static int iwm_wext_giwencode(struct net_device *dev,
356 struct iw_request_info *info,
357 struct iw_point *erq, char *key)
359 struct iwm_priv *iwm = ndev_to_iwm(dev);
362 idx = erq->flags & IW_ENCODE_INDEX;
363 if (idx < 1 || idx > 4) {
365 if (!iwm->default_key) {
367 erq->flags |= IW_ENCODE_NOKEY;
370 for (i = 0; i < IWM_NUM_KEYS; i++) {
371 if (iwm->default_key == &iwm->keys[i]) {
381 erq->flags = idx + 1;
383 if (!iwm->keys[idx].in_use) {
385 erq->flags |= IW_ENCODE_DISABLED;
389 memcpy(key, iwm->keys[idx].key,
390 min_t(int, erq->length, iwm->keys[idx].key_len));
391 erq->length = iwm->keys[idx].key_len;
392 erq->flags |= IW_ENCODE_ENABLED;
394 if (iwm->umac_profile->mode == UMAC_MODE_BSS) {
395 switch (iwm->umac_profile->sec.auth_type) {
396 case UMAC_AUTH_TYPE_OPEN:
397 erq->flags |= IW_ENCODE_OPEN;
400 erq->flags |= IW_ENCODE_RESTRICTED;
408 static int iwm_set_wpa_version(struct iwm_priv *iwm, u8 wpa_version)
410 if (wpa_version & IW_AUTH_WPA_VERSION_WPA2)
411 iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK;
412 else if (wpa_version & IW_AUTH_WPA_VERSION_WPA)
413 iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK;
415 iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE;
420 static int iwm_wext_siwpower(struct net_device *dev,
421 struct iw_request_info *info,
422 struct iw_param *wrq, char *extra)
424 struct iwm_priv *iwm = ndev_to_iwm(dev);
428 power_index = IWM_POWER_INDEX_MIN;
431 power_index = IWM_POWER_INDEX_DEFAULT;
433 switch (wrq->flags & IW_POWER_MODE) {
443 if (power_index == iwm->conf.power_index)
446 iwm->conf.power_index = power_index;
448 return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
449 CFG_POWER_INDEX, iwm->conf.power_index);
452 static int iwm_wext_giwpower(struct net_device *dev,
453 struct iw_request_info *info,
454 union iwreq_data *wrqu, char *extra)
456 struct iwm_priv *iwm = ndev_to_iwm(dev);
458 wrqu->power.disabled = (iwm->conf.power_index == IWM_POWER_INDEX_MIN);
463 static int iwm_set_key_mgt(struct iwm_priv *iwm, u8 key_mgt)
465 u8 *auth_type = &iwm->umac_profile->sec.auth_type;
467 if (key_mgt == IW_AUTH_KEY_MGMT_802_1X)
468 *auth_type = UMAC_AUTH_TYPE_8021X;
469 else if (key_mgt == IW_AUTH_KEY_MGMT_PSK) {
470 if (iwm->umac_profile->sec.flags &
471 (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK))
472 *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
474 *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
476 IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt);
483 static int iwm_set_cipher(struct iwm_priv *iwm, u8 cipher, u8 ucast)
485 u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher :
486 &iwm->umac_profile->sec.mcast_cipher;
489 case IW_AUTH_CIPHER_NONE:
490 *profile_cipher = UMAC_CIPHER_TYPE_NONE;
492 case IW_AUTH_CIPHER_WEP40:
493 *profile_cipher = UMAC_CIPHER_TYPE_WEP_40;
495 case IW_AUTH_CIPHER_TKIP:
496 *profile_cipher = UMAC_CIPHER_TYPE_TKIP;
498 case IW_AUTH_CIPHER_CCMP:
499 *profile_cipher = UMAC_CIPHER_TYPE_CCMP;
501 case IW_AUTH_CIPHER_WEP104:
502 *profile_cipher = UMAC_CIPHER_TYPE_WEP_104;
505 IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher);
512 static int iwm_set_auth_alg(struct iwm_priv *iwm, u8 auth_alg)
514 u8 *auth_type = &iwm->umac_profile->sec.auth_type;
517 case IW_AUTH_ALG_OPEN_SYSTEM:
518 *auth_type = UMAC_AUTH_TYPE_OPEN;
520 case IW_AUTH_ALG_SHARED_KEY:
521 if (iwm->umac_profile->sec.flags &
522 (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) {
523 if (*auth_type == UMAC_AUTH_TYPE_8021X)
525 *auth_type = UMAC_AUTH_TYPE_RSNA_PSK;
527 *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK;
530 case IW_AUTH_ALG_LEAP:
532 IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", auth_alg);
539 static int iwm_wext_siwauth(struct net_device *dev,
540 struct iw_request_info *info,
541 struct iw_param *data, char *extra)
543 struct iwm_priv *iwm = ndev_to_iwm(dev);
547 (IW_AUTH_WPA_VERSION | IW_AUTH_KEY_MGMT |
548 IW_AUTH_WPA_ENABLED | IW_AUTH_80211_AUTH_ALG)) {
549 /* We need to invalidate the current profile */
550 if (iwm->umac_profile_active) {
551 ret = iwm_invalidate_mlme_profile(iwm);
553 IWM_ERR(iwm, "Couldn't invalidate profile\n");
559 switch (data->flags & IW_AUTH_INDEX) {
560 case IW_AUTH_WPA_VERSION:
561 return iwm_set_wpa_version(iwm, data->value);
563 case IW_AUTH_CIPHER_PAIRWISE:
564 return iwm_set_cipher(iwm, data->value, 1);
566 case IW_AUTH_CIPHER_GROUP:
567 return iwm_set_cipher(iwm, data->value, 0);
569 case IW_AUTH_KEY_MGMT:
570 return iwm_set_key_mgt(iwm, data->value);
572 case IW_AUTH_80211_AUTH_ALG:
573 return iwm_set_auth_alg(iwm, data->value);
582 static int iwm_wext_giwauth(struct net_device *dev,
583 struct iw_request_info *info,
584 struct iw_param *data, char *extra)
589 static int iwm_wext_siwencodeext(struct net_device *dev,
590 struct iw_request_info *info,
591 struct iw_point *erq, char *extra)
593 struct iwm_priv *iwm = ndev_to_iwm(dev);
595 struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
596 int uninitialized_var(alg), idx, i, remove = 0;
598 IWM_DBG_WEXT(iwm, DBG, "alg: 0x%x\n", ext->alg);
599 IWM_DBG_WEXT(iwm, DBG, "key len: %d\n", ext->key_len);
600 IWM_DBG_WEXT(iwm, DBG, "ext_flags: 0x%x\n", ext->ext_flags);
601 IWM_DBG_WEXT(iwm, DBG, "flags: 0x%x\n", erq->flags);
602 IWM_DBG_WEXT(iwm, DBG, "length: 0x%x\n", erq->length);
605 case IW_ENCODE_ALG_NONE:
608 case IW_ENCODE_ALG_WEP:
609 if (ext->key_len == WLAN_KEY_LEN_WEP40)
610 alg = UMAC_CIPHER_TYPE_WEP_40;
611 else if (ext->key_len == WLAN_KEY_LEN_WEP104)
612 alg = UMAC_CIPHER_TYPE_WEP_104;
614 IWM_ERR(iwm, "Invalid key length: %d\n", ext->key_len);
619 case IW_ENCODE_ALG_TKIP:
620 alg = UMAC_CIPHER_TYPE_TKIP;
622 case IW_ENCODE_ALG_CCMP:
623 alg = UMAC_CIPHER_TYPE_CCMP;
629 idx = erq->flags & IW_ENCODE_INDEX;
632 if (iwm->default_key)
633 for (i = 0; i < IWM_NUM_KEYS; i++) {
634 if (iwm->default_key == &iwm->keys[i]) {
639 } else if (idx < 1 || idx > 4) {
644 if (erq->flags & IW_ENCODE_DISABLED)
646 else if ((erq->length == 0) ||
647 (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) {
648 iwm->default_key = &iwm->keys[idx];
649 if (iwm->umac_profile_active && ext->alg == IW_ENCODE_ALG_WEP)
650 return iwm_set_tx_key(iwm, idx);
653 key = iwm_key_init(iwm, idx, !remove, ext, alg);
655 return iwm_set_key(iwm, remove, !iwm->default_key, key);
658 static const iw_handler iwm_handlers[] =
660 (iw_handler) NULL, /* SIOCSIWCOMMIT */
661 (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */
662 (iw_handler) NULL, /* SIOCSIWNWID */
663 (iw_handler) NULL, /* SIOCGIWNWID */
664 (iw_handler) iwm_wext_siwfreq, /* SIOCSIWFREQ */
665 (iw_handler) iwm_wext_giwfreq, /* SIOCGIWFREQ */
666 (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */
667 (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */
668 (iw_handler) NULL, /* SIOCSIWSENS */
669 (iw_handler) NULL, /* SIOCGIWSENS */
670 (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */
671 (iw_handler) cfg80211_wext_giwrange, /* SIOCGIWRANGE */
672 (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */
673 (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */
674 (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */
675 (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */
676 (iw_handler) NULL, /* SIOCSIWSPY */
677 (iw_handler) NULL, /* SIOCGIWSPY */
678 (iw_handler) NULL, /* SIOCSIWTHRSPY */
679 (iw_handler) NULL, /* SIOCGIWTHRSPY */
680 (iw_handler) iwm_wext_siwap, /* SIOCSIWAP */
681 (iw_handler) iwm_wext_giwap, /* SIOCGIWAP */
682 (iw_handler) NULL, /* SIOCSIWMLME */
683 (iw_handler) NULL, /* SIOCGIWAPLIST */
684 (iw_handler) cfg80211_wext_siwscan, /* SIOCSIWSCAN */
685 (iw_handler) cfg80211_wext_giwscan, /* SIOCGIWSCAN */
686 (iw_handler) iwm_wext_siwessid, /* SIOCSIWESSID */
687 (iw_handler) iwm_wext_giwessid, /* SIOCGIWESSID */
688 (iw_handler) NULL, /* SIOCSIWNICKN */
689 (iw_handler) NULL, /* SIOCGIWNICKN */
690 (iw_handler) NULL, /* -- hole -- */
691 (iw_handler) NULL, /* -- hole -- */
692 (iw_handler) NULL, /* SIOCSIWRATE */
693 (iw_handler) iwm_wext_giwrate, /* SIOCGIWRATE */
694 (iw_handler) cfg80211_wext_siwrts, /* SIOCSIWRTS */
695 (iw_handler) cfg80211_wext_giwrts, /* SIOCGIWRTS */
696 (iw_handler) cfg80211_wext_siwfrag, /* SIOCSIWFRAG */
697 (iw_handler) cfg80211_wext_giwfrag, /* SIOCGIWFRAG */
698 (iw_handler) NULL, /* SIOCSIWTXPOW */
699 (iw_handler) NULL, /* SIOCGIWTXPOW */
700 (iw_handler) NULL, /* SIOCSIWRETRY */
701 (iw_handler) NULL, /* SIOCGIWRETRY */
702 (iw_handler) iwm_wext_siwencode, /* SIOCSIWENCODE */
703 (iw_handler) iwm_wext_giwencode, /* SIOCGIWENCODE */
704 (iw_handler) iwm_wext_siwpower, /* SIOCSIWPOWER */
705 (iw_handler) iwm_wext_giwpower, /* SIOCGIWPOWER */
706 (iw_handler) NULL, /* -- hole -- */
707 (iw_handler) NULL, /* -- hole -- */
708 (iw_handler) NULL, /* SIOCSIWGENIE */
709 (iw_handler) NULL, /* SIOCGIWGENIE */
710 (iw_handler) iwm_wext_siwauth, /* SIOCSIWAUTH */
711 (iw_handler) iwm_wext_giwauth, /* SIOCGIWAUTH */
712 (iw_handler) iwm_wext_siwencodeext, /* SIOCSIWENCODEEXT */
713 (iw_handler) NULL, /* SIOCGIWENCODEEXT */
714 (iw_handler) NULL, /* SIOCSIWPMKSA */
715 (iw_handler) NULL, /* -- hole -- */
718 const struct iw_handler_def iwm_iw_handler_def = {
719 .num_standard = ARRAY_SIZE(iwm_handlers),
720 .standard = (iw_handler *) iwm_handlers,
721 .get_wireless_stats = iwm_get_wireless_stats,