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