• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "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
set80211priv(struct wpa_driver_madwifi_data * drv,int op,void * data,int len,int show_err)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
set80211param(struct wpa_driver_madwifi_data * drv,int op,int arg,int show_err)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
wpa_driver_madwifi_set_wpa_ie(struct wpa_driver_madwifi_data * drv,const u8 * wpa_ie,size_t wpa_ie_len)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
wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data * drv,int key_idx,const u8 * addr)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
wpa_driver_madwifi_set_key(void * priv,wpa_alg alg,const u8 * addr,int key_idx,int set_tx,const u8 * seq,size_t seq_len,const u8 * key,size_t key_len)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
wpa_driver_madwifi_set_countermeasures(void * priv,int enabled)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
wpa_driver_madwifi_set_drop_unencrypted(void * priv,int enabled)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
wpa_driver_madwifi_deauthenticate(void * priv,const u8 * addr,int reason_code)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
wpa_driver_madwifi_disassociate(void * priv,const u8 * addr,int reason_code)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
wpa_driver_madwifi_associate(void * priv,struct wpa_driver_associate_params * params)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
wpa_driver_madwifi_set_auth_alg(void * priv,int auth_alg)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
wpa_driver_madwifi_scan(void * priv,const u8 * ssid,size_t ssid_len)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 
wpa_driver_madwifi_get_bssid(void * priv,u8 * bssid)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 
wpa_driver_madwifi_get_ssid(void * priv,u8 * ssid)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 
wpa_driver_madwifi_get_scan_results(void * priv,struct wpa_scan_result * results,size_t max_size)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 
wpa_driver_madwifi_set_operstate(void * priv,int state)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 
wpa_driver_madwifi_init(void * ctx,const char * ifname)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 
wpa_driver_madwifi_deinit(void * priv)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