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