cc6f27e7fe205deeccfec86a56f14af11cce7a88
[wpasupplicant] / src / drivers / driver_madwifi.c
1 /*
2  * WPA Supplicant - driver interaction with MADWIFI 802.11 driver
3  * Copyright (c) 2004, Sam Leffler <sam@errno.com>
4  * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * Alternatively, this software may be distributed under the terms of BSD
11  * license.
12  *
13  * See README and COPYING for more details.
14  */
15
16 #include "includes.h"
17 #include <sys/ioctl.h>
18
19 #include "common.h"
20 #include "driver.h"
21 #include "driver_wext.h"
22 #include "eloop.h"
23 #include "ieee802_11_defs.h"
24 #include "wireless_copy.h"
25
26 /*
27  * Avoid conflicts with wpa_supplicant definitions by undefining a definition.
28  */
29 #undef WME_OUI_TYPE
30
31 #include <include/compat.h>
32 #include <net80211/ieee80211.h>
33 #ifdef WME_NUM_AC
34 /* Assume this is built against BSD branch of madwifi driver. */
35 #define MADWIFI_BSD
36 #include <net80211/_ieee80211.h>
37 #endif /* WME_NUM_AC */
38 #include <net80211/ieee80211_crypto.h>
39 #include <net80211/ieee80211_ioctl.h>
40
41
42 #ifdef IEEE80211_IOCTL_SETWMMPARAMS
43 /* Assume this is built against madwifi-ng */
44 #define MADWIFI_NG
45 #endif /* IEEE80211_IOCTL_SETWMMPARAMS */
46
47 struct wpa_driver_madwifi_data {
48         void *wext; /* private data for driver_wext */
49         void *ctx;
50         char ifname[IFNAMSIZ + 1];
51         int sock;
52 };
53
54 static int
55 set80211priv(struct wpa_driver_madwifi_data *drv, int op, void *data, int len,
56              int show_err)
57 {
58         struct iwreq iwr;
59
60         os_memset(&iwr, 0, sizeof(iwr));
61         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
62         if (len < IFNAMSIZ &&
63             op != IEEE80211_IOCTL_SET_APPIEBUF) {
64                 /*
65                  * Argument data fits inline; put it there.
66                  */
67                 os_memcpy(iwr.u.name, data, len);
68         } else {
69                 /*
70                  * Argument data too big for inline transfer; setup a
71                  * parameter block instead; the kernel will transfer
72                  * the data for the driver.
73                  */
74                 iwr.u.data.pointer = data;
75                 iwr.u.data.length = len;
76         }
77
78         if (ioctl(drv->sock, op, &iwr) < 0) {
79                 if (show_err) {
80 #ifdef MADWIFI_NG
81                         int first = IEEE80211_IOCTL_SETPARAM;
82                         int last = IEEE80211_IOCTL_KICKMAC;
83                         static const char *opnames[] = {
84                                 "ioctl[IEEE80211_IOCTL_SETPARAM]",
85                                 "ioctl[IEEE80211_IOCTL_GETPARAM]",
86                                 "ioctl[IEEE80211_IOCTL_SETMODE]",
87                                 "ioctl[IEEE80211_IOCTL_GETMODE]",
88                                 "ioctl[IEEE80211_IOCTL_SETWMMPARAMS]",
89                                 "ioctl[IEEE80211_IOCTL_GETWMMPARAMS]",
90                                 "ioctl[IEEE80211_IOCTL_SETCHANLIST]",
91                                 "ioctl[IEEE80211_IOCTL_GETCHANLIST]",
92                                 "ioctl[IEEE80211_IOCTL_CHANSWITCH]",
93                                 NULL,
94                                 "ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
95                                 "ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
96                                 NULL,
97                                 "ioctl[IEEE80211_IOCTL_GETCHANINFO]",
98                                 "ioctl[IEEE80211_IOCTL_SETOPTIE]",
99                                 "ioctl[IEEE80211_IOCTL_GETOPTIE]",
100                                 "ioctl[IEEE80211_IOCTL_SETMLME]",
101                                 NULL,
102                                 "ioctl[IEEE80211_IOCTL_SETKEY]",
103                                 NULL,
104                                 "ioctl[IEEE80211_IOCTL_DELKEY]",
105                                 NULL,
106                                 "ioctl[IEEE80211_IOCTL_ADDMAC]",
107                                 NULL,
108                                 "ioctl[IEEE80211_IOCTL_DELMAC]",
109                                 NULL,
110                                 "ioctl[IEEE80211_IOCTL_WDSMAC]",
111                                 NULL,
112                                 "ioctl[IEEE80211_IOCTL_WDSDELMAC]",
113                                 NULL,
114                                 "ioctl[IEEE80211_IOCTL_KICKMAC]",
115                         };
116 #else /* MADWIFI_NG */
117                         int first = IEEE80211_IOCTL_SETPARAM;
118                         int last = IEEE80211_IOCTL_CHANLIST;
119                         static const char *opnames[] = {
120                                 "ioctl[IEEE80211_IOCTL_SETPARAM]",
121                                 "ioctl[IEEE80211_IOCTL_GETPARAM]",
122                                 "ioctl[IEEE80211_IOCTL_SETKEY]",
123                                 "ioctl[IEEE80211_IOCTL_GETKEY]",
124                                 "ioctl[IEEE80211_IOCTL_DELKEY]",
125                                 NULL,
126                                 "ioctl[IEEE80211_IOCTL_SETMLME]",
127                                 NULL,
128                                 "ioctl[IEEE80211_IOCTL_SETOPTIE]",
129                                 "ioctl[IEEE80211_IOCTL_GETOPTIE]",
130                                 "ioctl[IEEE80211_IOCTL_ADDMAC]",
131                                 NULL,
132                                 "ioctl[IEEE80211_IOCTL_DELMAC]",
133                                 NULL,
134                                 "ioctl[IEEE80211_IOCTL_CHANLIST]",
135                         };
136 #endif /* MADWIFI_NG */
137                         int idx = op - first;
138                         if (first <= op && op <= last &&
139                             idx < (int) (sizeof(opnames) / sizeof(opnames[0]))
140                             && opnames[idx])
141                                 perror(opnames[idx]);
142                         else
143                                 perror("ioctl[unknown???]");
144                 }
145                 return -1;
146         }
147         return 0;
148 }
149
150 static int
151 set80211param(struct wpa_driver_madwifi_data *drv, int op, int arg,
152               int show_err)
153 {
154         struct iwreq iwr;
155
156         os_memset(&iwr, 0, sizeof(iwr));
157         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
158         iwr.u.mode = op;
159         os_memcpy(iwr.u.name+sizeof(u32), &arg, sizeof(arg));
160
161         if (ioctl(drv->sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
162                 if (show_err) 
163                         perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
164                 return -1;
165         }
166         return 0;
167 }
168
169 static int
170 wpa_driver_madwifi_set_wpa_ie(struct wpa_driver_madwifi_data *drv,
171                               const u8 *wpa_ie, size_t wpa_ie_len)
172 {
173         struct iwreq iwr;
174
175         os_memset(&iwr, 0, sizeof(iwr));
176         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
177         /* NB: SETOPTIE is not fixed-size so must not be inlined */
178         iwr.u.data.pointer = (void *) wpa_ie;
179         iwr.u.data.length = wpa_ie_len;
180
181         if (ioctl(drv->sock, IEEE80211_IOCTL_SETOPTIE, &iwr) < 0) {
182                 perror("ioctl[IEEE80211_IOCTL_SETOPTIE]");
183                 return -1;
184         }
185         return 0;
186 }
187
188 static int
189 wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data *drv, int key_idx,
190                            const u8 *addr)
191 {
192         struct ieee80211req_del_key wk;
193
194         wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __FUNCTION__, key_idx);
195         os_memset(&wk, 0, sizeof(wk));
196         wk.idk_keyix = key_idx;
197         if (addr != NULL)
198                 os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
199
200         return set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk), 1);
201 }
202
203 static int
204 wpa_driver_madwifi_set_key(void *priv, wpa_alg alg,
205                            const u8 *addr, int key_idx, int set_tx,
206                            const u8 *seq, size_t seq_len,
207                            const u8 *key, size_t key_len)
208 {
209         struct wpa_driver_madwifi_data *drv = priv;
210         struct ieee80211req_key wk;
211         char *alg_name;
212         u_int8_t cipher;
213
214         if (alg == WPA_ALG_NONE)
215                 return wpa_driver_madwifi_del_key(drv, key_idx, addr);
216
217         switch (alg) {
218         case WPA_ALG_WEP:
219                 if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
220                                               ETH_ALEN) == 0) {
221                         /*
222                          * madwifi did not seem to like static WEP key
223                          * configuration with IEEE80211_IOCTL_SETKEY, so use
224                          * Linux wireless extensions ioctl for this.
225                          */
226                         return wpa_driver_wext_set_key(drv->wext, alg, addr,
227                                                        key_idx, set_tx,
228                                                        seq, seq_len,
229                                                        key, key_len);
230                 }
231                 alg_name = "WEP";
232                 cipher = IEEE80211_CIPHER_WEP;
233                 break;
234         case WPA_ALG_TKIP:
235                 alg_name = "TKIP";
236                 cipher = IEEE80211_CIPHER_TKIP;
237                 break;
238         case WPA_ALG_CCMP:
239                 alg_name = "CCMP";
240                 cipher = IEEE80211_CIPHER_AES_CCM;
241                 break;
242         default:
243                 wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
244                         __FUNCTION__, alg);
245                 return -1;
246         }
247
248         wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
249                    "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
250                    (unsigned long) seq_len, (unsigned long) key_len);
251
252         if (seq_len > sizeof(u_int64_t)) {
253                 wpa_printf(MSG_DEBUG, "%s: seq_len %lu too big",
254                            __FUNCTION__, (unsigned long) seq_len);
255                 return -2;
256         }
257         if (key_len > sizeof(wk.ik_keydata)) {
258                 wpa_printf(MSG_DEBUG, "%s: key length %lu too big",
259                            __FUNCTION__, (unsigned long) key_len);
260                 return -3;
261         }
262
263         os_memset(&wk, 0, sizeof(wk));
264         wk.ik_type = cipher;
265         wk.ik_flags = IEEE80211_KEY_RECV;
266         if (addr == NULL ||
267             os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
268                 wk.ik_flags |= IEEE80211_KEY_GROUP;
269         if (set_tx) {
270                 wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
271                 os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
272         } else
273                 os_memset(wk.ik_macaddr, 0, IEEE80211_ADDR_LEN);
274         wk.ik_keyix = key_idx;
275         wk.ik_keylen = key_len;
276 #ifdef WORDS_BIGENDIAN
277 #define WPA_KEY_RSC_LEN 8
278         {
279                 size_t i;
280                 u8 tmp[WPA_KEY_RSC_LEN];
281                 os_memset(tmp, 0, sizeof(tmp));
282                 for (i = 0; i < seq_len; i++)
283                         tmp[WPA_KEY_RSC_LEN - i - 1] = seq[i];
284                 os_memcpy(&wk.ik_keyrsc, tmp, WPA_KEY_RSC_LEN);
285         }
286 #else /* WORDS_BIGENDIAN */
287         os_memcpy(&wk.ik_keyrsc, seq, seq_len);
288 #endif /* WORDS_BIGENDIAN */
289         os_memcpy(wk.ik_keydata, key, key_len);
290
291         return set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk), 1);
292 }
293
294 static int
295 wpa_driver_madwifi_set_countermeasures(void *priv, int enabled)
296 {
297         struct wpa_driver_madwifi_data *drv = priv;
298         wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
299         return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled, 1);
300 }
301
302
303 static int
304 wpa_driver_madwifi_set_drop_unencrypted(void *priv, int enabled)
305 {
306         struct wpa_driver_madwifi_data *drv = priv;
307         wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
308         return set80211param(drv, IEEE80211_PARAM_DROPUNENCRYPTED, enabled, 1);
309 }
310
311 static int
312 wpa_driver_madwifi_deauthenticate(void *priv, const u8 *addr, int reason_code)
313 {
314         struct wpa_driver_madwifi_data *drv = priv;
315         struct ieee80211req_mlme mlme;
316
317         wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
318         mlme.im_op = IEEE80211_MLME_DEAUTH;
319         mlme.im_reason = reason_code;
320         os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
321         return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
322 }
323
324 static int
325 wpa_driver_madwifi_disassociate(void *priv, const u8 *addr, int reason_code)
326 {
327         struct wpa_driver_madwifi_data *drv = priv;
328         struct ieee80211req_mlme mlme;
329
330         wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
331         mlme.im_op = IEEE80211_MLME_DISASSOC;
332         mlme.im_reason = reason_code;
333         os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
334         return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
335 }
336
337 static int
338 wpa_driver_madwifi_associate(void *priv,
339                              struct wpa_driver_associate_params *params)
340 {
341         struct wpa_driver_madwifi_data *drv = priv;
342         struct ieee80211req_mlme mlme;
343         int ret = 0, privacy = 1;
344
345         wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
346
347         /*
348          * NB: Don't need to set the freq or cipher-related state as
349          *     this is implied by the bssid which is used to locate
350          *     the scanned node state which holds it.  The ssid is
351          *     needed to disambiguate an AP that broadcasts multiple
352          *     ssid's but uses the same bssid.
353          */
354         /* XXX error handling is wrong but unclear what to do... */
355         if (wpa_driver_madwifi_set_wpa_ie(drv, params->wpa_ie,
356                                           params->wpa_ie_len) < 0)
357                 ret = -1;
358
359         if (params->pairwise_suite == CIPHER_NONE &&
360             params->group_suite == CIPHER_NONE &&
361             params->key_mgmt_suite == KEY_MGMT_NONE &&
362             params->wpa_ie_len == 0)
363                 privacy = 0;
364
365         if (set80211param(drv, IEEE80211_PARAM_PRIVACY, privacy, 1) < 0)
366                 ret = -1;
367
368         if (params->wpa_ie_len &&
369             set80211param(drv, IEEE80211_PARAM_WPA,
370                           params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1, 1) < 0)
371                 ret = -1;
372
373         if (params->bssid == NULL) {
374                 /* ap_scan=2 mode - driver takes care of AP selection and
375                  * roaming */
376                 /* FIX: this does not seem to work; would probably need to
377                  * change something in the driver */
378                 if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0)
379                         ret = -1;
380
381                 if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
382                                              params->ssid_len) < 0)
383                         ret = -1;
384         } else {
385                 if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0)
386                         ret = -1;
387                 if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
388                                              params->ssid_len) < 0)
389                         ret = -1;
390                 os_memset(&mlme, 0, sizeof(mlme));
391                 mlme.im_op = IEEE80211_MLME_ASSOC;
392                 os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
393                 if (set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
394                                  sizeof(mlme), 1) < 0) {
395                         wpa_printf(MSG_DEBUG, "%s: SETMLME[ASSOC] failed",
396                                    __func__);
397                         ret = -1;
398                 }
399         }
400
401         return ret;
402 }
403
404 static int
405 wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg)
406 {
407         struct wpa_driver_madwifi_data *drv = priv;
408         int authmode;
409
410         if ((auth_alg & AUTH_ALG_OPEN_SYSTEM) &&
411             (auth_alg & AUTH_ALG_SHARED_KEY))
412                 authmode = IEEE80211_AUTH_AUTO;
413         else if (auth_alg & AUTH_ALG_SHARED_KEY)
414                 authmode = IEEE80211_AUTH_SHARED;
415         else
416                 authmode = IEEE80211_AUTH_OPEN;
417
418         return set80211param(drv, IEEE80211_PARAM_AUTHMODE, authmode, 1);
419 }
420
421 static int
422 wpa_driver_madwifi_scan(void *priv, const u8 *ssid, size_t ssid_len)
423 {
424         struct wpa_driver_madwifi_data *drv = priv;
425         struct iwreq iwr;
426         int ret = 0;
427
428         os_memset(&iwr, 0, sizeof(iwr));
429         os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
430
431         /* set desired ssid before scan */
432         /* FIX: scan should not break the current association, so using
433          * set_ssid may not be the best way of doing this.. */
434         if (wpa_driver_wext_set_ssid(drv->wext, ssid, ssid_len) < 0)
435                 ret = -1;
436
437         if (ioctl(drv->sock, SIOCSIWSCAN, &iwr) < 0) {
438                 perror("ioctl[SIOCSIWSCAN]");
439                 ret = -1;
440         }
441
442         /*
443          * madwifi delivers a scan complete event so no need to poll, but
444          * register a backup timeout anyway to make sure that we recover even
445          * if the driver does not send this event for any reason. This timeout
446          * will only be used if the event is not delivered (event handler will
447          * cancel the timeout).
448          */
449         eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
450                              drv->ctx);
451         eloop_register_timeout(30, 0, wpa_driver_wext_scan_timeout, drv->wext,
452                                drv->ctx);
453
454         return ret;
455 }
456
457 static int wpa_driver_madwifi_get_bssid(void *priv, u8 *bssid)
458 {
459         struct wpa_driver_madwifi_data *drv = priv;
460         return wpa_driver_wext_get_bssid(drv->wext, bssid);
461 }
462
463
464 static int wpa_driver_madwifi_get_ssid(void *priv, u8 *ssid)
465 {
466         struct wpa_driver_madwifi_data *drv = priv;
467         return wpa_driver_wext_get_ssid(drv->wext, ssid);
468 }
469
470
471 static struct wpa_scan_results *
472 wpa_driver_madwifi_get_scan_results(void *priv)
473 {
474         struct wpa_driver_madwifi_data *drv = priv;
475         return wpa_driver_wext_get_scan_results(drv->wext);
476 }
477
478
479 static int wpa_driver_madwifi_set_operstate(void *priv, int state)
480 {
481         struct wpa_driver_madwifi_data *drv = priv;
482         return wpa_driver_wext_set_operstate(drv->wext, state);
483 }
484
485
486 static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies,
487                                                size_t ies_len)
488 {
489         struct ieee80211req_getset_appiebuf *probe_req_ie;
490         int ret;
491
492         probe_req_ie = os_malloc(sizeof(*probe_req_ie) + ies_len);
493         if (probe_req_ie == NULL)
494                 return -1;
495
496         probe_req_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_REQ;
497         probe_req_ie->app_buflen = ies_len;
498         os_memcpy(probe_req_ie->app_buf, ies, ies_len);
499
500         ret = set80211priv(priv, IEEE80211_IOCTL_SET_APPIEBUF, probe_req_ie,
501                            sizeof(struct ieee80211req_getset_appiebuf) +
502                            ies_len, 1);
503
504         os_free(probe_req_ie);
505
506         return ret;
507 }
508
509
510 static void * wpa_driver_madwifi_init(void *ctx, const char *ifname)
511 {
512         struct wpa_driver_madwifi_data *drv;
513
514         drv = os_zalloc(sizeof(*drv));
515         if (drv == NULL)
516                 return NULL;
517         drv->wext = wpa_driver_wext_init(ctx, ifname);
518         if (drv->wext == NULL)
519                 goto fail;
520
521         drv->ctx = ctx;
522         os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
523         drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
524         if (drv->sock < 0)
525                 goto fail2;
526
527         if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0) {
528                 wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
529                            "roaming", __FUNCTION__);
530                 goto fail3;
531         }
532
533         if (set80211param(drv, IEEE80211_PARAM_WPA, 3, 1) < 0) {
534                 wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support",
535                            __FUNCTION__);
536                 goto fail3;
537         }
538
539         return drv;
540
541 fail3:
542         close(drv->sock);
543 fail2:
544         wpa_driver_wext_deinit(drv->wext);
545 fail:
546         os_free(drv);
547         return NULL;
548 }
549
550
551 static void wpa_driver_madwifi_deinit(void *priv)
552 {
553         struct wpa_driver_madwifi_data *drv = priv;
554
555         if (wpa_driver_madwifi_set_wpa_ie(drv, NULL, 0) < 0) {
556                 wpa_printf(MSG_DEBUG, "%s: failed to clear WPA IE",
557                            __FUNCTION__);
558         }
559         if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0) {
560                 wpa_printf(MSG_DEBUG, "%s: failed to enable driver-based "
561                            "roaming", __FUNCTION__);
562         }
563         if (set80211param(drv, IEEE80211_PARAM_PRIVACY, 0, 1) < 0) {
564                 wpa_printf(MSG_DEBUG, "%s: failed to disable forced Privacy "
565                            "flag", __FUNCTION__);
566         }
567         if (set80211param(drv, IEEE80211_PARAM_WPA, 0, 1) < 0) {
568                 wpa_printf(MSG_DEBUG, "%s: failed to disable WPA",
569                            __FUNCTION__);
570         }
571
572         wpa_driver_wext_deinit(drv->wext);
573
574         close(drv->sock);
575         os_free(drv);
576 }
577
578
579 const struct wpa_driver_ops wpa_driver_madwifi_ops = {
580         .name                   = "madwifi",
581         .desc                   = "MADWIFI 802.11 support (Atheros, etc.)",
582         .get_bssid              = wpa_driver_madwifi_get_bssid,
583         .get_ssid               = wpa_driver_madwifi_get_ssid,
584         .set_key                = wpa_driver_madwifi_set_key,
585         .init                   = wpa_driver_madwifi_init,
586         .deinit                 = wpa_driver_madwifi_deinit,
587         .set_countermeasures    = wpa_driver_madwifi_set_countermeasures,
588         .set_drop_unencrypted   = wpa_driver_madwifi_set_drop_unencrypted,
589         .scan                   = wpa_driver_madwifi_scan,
590         .get_scan_results2      = wpa_driver_madwifi_get_scan_results,
591         .deauthenticate         = wpa_driver_madwifi_deauthenticate,
592         .disassociate           = wpa_driver_madwifi_disassociate,
593         .associate              = wpa_driver_madwifi_associate,
594         .set_auth_alg           = wpa_driver_madwifi_set_auth_alg,
595         .set_operstate          = wpa_driver_madwifi_set_operstate,
596         .set_probe_req_ie       = wpa_driver_madwifi_set_probe_req_ie,
597 };