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>
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.
10 * Alternatively, this software may be distributed under the terms of BSD
13 * See README and COPYING for more details.
17 #include <sys/ioctl.h>
21 #include "driver_wext.h"
23 #include "ieee802_11_defs.h"
24 #include "wireless_copy.h"
26 #include <include/compat.h>
27 #include <net80211/ieee80211.h>
29 /* Assume this is built against BSD branch of madwifi driver. */
31 #include <net80211/_ieee80211.h>
32 #endif /* WME_NUM_AC */
33 #include <net80211/ieee80211_crypto.h>
34 #include <net80211/ieee80211_ioctl.h>
36 #ifdef IEEE80211_IOCTL_SETWMMPARAMS
37 /* Assume this is built against madwifi-ng */
39 #endif /* IEEE80211_IOCTL_SETWMMPARAMS */
41 struct wpa_driver_madwifi_data
{
42 void *wext
; /* private data for driver_wext */
44 char ifname
[IFNAMSIZ
+ 1];
49 set80211priv(struct wpa_driver_madwifi_data
*drv
, int op
, void *data
, int len
,
54 os_memset(&iwr
, 0, sizeof(iwr
));
55 os_strlcpy(iwr
.ifr_name
, drv
->ifname
, IFNAMSIZ
);
58 * Argument data fits inline; put it there.
60 os_memcpy(iwr
.u
.name
, data
, len
);
63 * Argument data too big for inline transfer; setup a
64 * parameter block instead; the kernel will transfer
65 * the data for the driver.
67 iwr
.u
.data
.pointer
= data
;
68 iwr
.u
.data
.length
= len
;
71 if (ioctl(drv
->sock
, op
, &iwr
) < 0) {
74 int first
= IEEE80211_IOCTL_SETPARAM
;
75 int last
= IEEE80211_IOCTL_KICKMAC
;
76 static const char *opnames
[] = {
77 "ioctl[IEEE80211_IOCTL_SETPARAM]",
78 "ioctl[IEEE80211_IOCTL_GETPARAM]",
79 "ioctl[IEEE80211_IOCTL_SETMODE]",
80 "ioctl[IEEE80211_IOCTL_GETMODE]",
81 "ioctl[IEEE80211_IOCTL_SETWMMPARAMS]",
82 "ioctl[IEEE80211_IOCTL_GETWMMPARAMS]",
83 "ioctl[IEEE80211_IOCTL_SETCHANLIST]",
84 "ioctl[IEEE80211_IOCTL_GETCHANLIST]",
85 "ioctl[IEEE80211_IOCTL_CHANSWITCH]",
88 "ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
90 "ioctl[IEEE80211_IOCTL_GETCHANINFO]",
91 "ioctl[IEEE80211_IOCTL_SETOPTIE]",
92 "ioctl[IEEE80211_IOCTL_GETOPTIE]",
93 "ioctl[IEEE80211_IOCTL_SETMLME]",
95 "ioctl[IEEE80211_IOCTL_SETKEY]",
97 "ioctl[IEEE80211_IOCTL_DELKEY]",
99 "ioctl[IEEE80211_IOCTL_ADDMAC]",
101 "ioctl[IEEE80211_IOCTL_DELMAC]",
103 "ioctl[IEEE80211_IOCTL_WDSMAC]",
105 "ioctl[IEEE80211_IOCTL_WDSDELMAC]",
107 "ioctl[IEEE80211_IOCTL_KICKMAC]",
109 #else /* MADWIFI_NG */
110 int first
= IEEE80211_IOCTL_SETPARAM
;
111 int last
= IEEE80211_IOCTL_CHANLIST
;
112 static const char *opnames
[] = {
113 "ioctl[IEEE80211_IOCTL_SETPARAM]",
114 "ioctl[IEEE80211_IOCTL_GETPARAM]",
115 "ioctl[IEEE80211_IOCTL_SETKEY]",
116 "ioctl[IEEE80211_IOCTL_GETKEY]",
117 "ioctl[IEEE80211_IOCTL_DELKEY]",
119 "ioctl[IEEE80211_IOCTL_SETMLME]",
121 "ioctl[IEEE80211_IOCTL_SETOPTIE]",
122 "ioctl[IEEE80211_IOCTL_GETOPTIE]",
123 "ioctl[IEEE80211_IOCTL_ADDMAC]",
125 "ioctl[IEEE80211_IOCTL_DELMAC]",
127 "ioctl[IEEE80211_IOCTL_CHANLIST]",
129 #endif /* MADWIFI_NG */
130 int idx
= op
- first
;
131 if (first
<= op
&& op
<= last
&&
132 idx
< (int) (sizeof(opnames
) / sizeof(opnames
[0]))
134 perror(opnames
[idx
]);
136 perror("ioctl[unknown???]");
144 set80211param(struct wpa_driver_madwifi_data
*drv
, int op
, int arg
,
149 os_memset(&iwr
, 0, sizeof(iwr
));
150 os_strlcpy(iwr
.ifr_name
, drv
->ifname
, IFNAMSIZ
);
152 os_memcpy(iwr
.u
.name
+sizeof(u32
), &arg
, sizeof(arg
));
154 if (ioctl(drv
->sock
, IEEE80211_IOCTL_SETPARAM
, &iwr
) < 0) {
156 perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
163 wpa_driver_madwifi_set_wpa_ie(struct wpa_driver_madwifi_data
*drv
,
164 const u8
*wpa_ie
, size_t wpa_ie_len
)
168 os_memset(&iwr
, 0, sizeof(iwr
));
169 os_strlcpy(iwr
.ifr_name
, drv
->ifname
, IFNAMSIZ
);
170 /* NB: SETOPTIE is not fixed-size so must not be inlined */
171 iwr
.u
.data
.pointer
= (void *) wpa_ie
;
172 iwr
.u
.data
.length
= wpa_ie_len
;
174 if (ioctl(drv
->sock
, IEEE80211_IOCTL_SETOPTIE
, &iwr
) < 0) {
175 perror("ioctl[IEEE80211_IOCTL_SETOPTIE]");
182 wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data
*drv
, int key_idx
,
185 struct ieee80211req_del_key wk
;
187 wpa_printf(MSG_DEBUG
, "%s: keyidx=%d", __FUNCTION__
, key_idx
);
188 os_memset(&wk
, 0, sizeof(wk
));
189 wk
.idk_keyix
= key_idx
;
191 os_memcpy(wk
.idk_macaddr
, addr
, IEEE80211_ADDR_LEN
);
193 return set80211priv(drv
, IEEE80211_IOCTL_DELKEY
, &wk
, sizeof(wk
), 1);
197 wpa_driver_madwifi_set_key(void *priv
, wpa_alg alg
,
198 const u8
*addr
, int key_idx
, int set_tx
,
199 const u8
*seq
, size_t seq_len
,
200 const u8
*key
, size_t key_len
)
202 struct wpa_driver_madwifi_data
*drv
= priv
;
203 struct ieee80211req_key wk
;
207 if (alg
== WPA_ALG_NONE
)
208 return wpa_driver_madwifi_del_key(drv
, key_idx
, addr
);
212 if (addr
== NULL
|| os_memcmp(addr
, "\xff\xff\xff\xff\xff\xff",
215 * madwifi did not seem to like static WEP key
216 * configuration with IEEE80211_IOCTL_SETKEY, so use
217 * Linux wireless extensions ioctl for this.
219 return wpa_driver_wext_set_key(drv
->wext
, alg
, addr
,
225 cipher
= IEEE80211_CIPHER_WEP
;
229 cipher
= IEEE80211_CIPHER_TKIP
;
233 cipher
= IEEE80211_CIPHER_AES_CCM
;
236 wpa_printf(MSG_DEBUG
, "%s: unknown/unsupported algorithm %d",
241 wpa_printf(MSG_DEBUG
, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
242 "key_len=%lu", __FUNCTION__
, alg_name
, key_idx
, set_tx
,
243 (unsigned long) seq_len
, (unsigned long) key_len
);
245 if (seq_len
> sizeof(u_int64_t
)) {
246 wpa_printf(MSG_DEBUG
, "%s: seq_len %lu too big",
247 __FUNCTION__
, (unsigned long) seq_len
);
250 if (key_len
> sizeof(wk
.ik_keydata
)) {
251 wpa_printf(MSG_DEBUG
, "%s: key length %lu too big",
252 __FUNCTION__
, (unsigned long) key_len
);
256 os_memset(&wk
, 0, sizeof(wk
));
258 wk
.ik_flags
= IEEE80211_KEY_RECV
;
260 os_memcmp(addr
, "\xff\xff\xff\xff\xff\xff", ETH_ALEN
) == 0)
261 wk
.ik_flags
|= IEEE80211_KEY_GROUP
;
263 wk
.ik_flags
|= IEEE80211_KEY_XMIT
| IEEE80211_KEY_DEFAULT
;
264 os_memcpy(wk
.ik_macaddr
, addr
, IEEE80211_ADDR_LEN
);
266 os_memset(wk
.ik_macaddr
, 0, IEEE80211_ADDR_LEN
);
267 wk
.ik_keyix
= key_idx
;
268 wk
.ik_keylen
= key_len
;
269 #ifdef WORDS_BIGENDIAN
270 #define WPA_KEY_RSC_LEN 8
273 u8 tmp
[WPA_KEY_RSC_LEN
];
274 os_memset(tmp
, 0, sizeof(tmp
));
275 for (i
= 0; i
< seq_len
; i
++)
276 tmp
[WPA_KEY_RSC_LEN
- i
- 1] = seq
[i
];
277 os_memcpy(&wk
.ik_keyrsc
, tmp
, WPA_KEY_RSC_LEN
);
279 #else /* WORDS_BIGENDIAN */
280 os_memcpy(&wk
.ik_keyrsc
, seq
, seq_len
);
281 #endif /* WORDS_BIGENDIAN */
282 os_memcpy(wk
.ik_keydata
, key
, key_len
);
284 return set80211priv(drv
, IEEE80211_IOCTL_SETKEY
, &wk
, sizeof(wk
), 1);
288 wpa_driver_madwifi_set_countermeasures(void *priv
, int enabled
)
290 struct wpa_driver_madwifi_data
*drv
= priv
;
291 wpa_printf(MSG_DEBUG
, "%s: enabled=%d", __FUNCTION__
, enabled
);
292 return set80211param(drv
, IEEE80211_PARAM_COUNTERMEASURES
, enabled
, 1);
297 wpa_driver_madwifi_set_drop_unencrypted(void *priv
, int enabled
)
299 struct wpa_driver_madwifi_data
*drv
= priv
;
300 wpa_printf(MSG_DEBUG
, "%s: enabled=%d", __FUNCTION__
, enabled
);
301 return set80211param(drv
, IEEE80211_PARAM_DROPUNENCRYPTED
, enabled
, 1);
305 wpa_driver_madwifi_deauthenticate(void *priv
, const u8
*addr
, int reason_code
)
307 struct wpa_driver_madwifi_data
*drv
= priv
;
308 struct ieee80211req_mlme mlme
;
310 wpa_printf(MSG_DEBUG
, "%s", __FUNCTION__
);
311 mlme
.im_op
= IEEE80211_MLME_DEAUTH
;
312 mlme
.im_reason
= reason_code
;
313 os_memcpy(mlme
.im_macaddr
, addr
, IEEE80211_ADDR_LEN
);
314 return set80211priv(drv
, IEEE80211_IOCTL_SETMLME
, &mlme
, sizeof(mlme
), 1);
318 wpa_driver_madwifi_disassociate(void *priv
, const u8
*addr
, int reason_code
)
320 struct wpa_driver_madwifi_data
*drv
= priv
;
321 struct ieee80211req_mlme mlme
;
323 wpa_printf(MSG_DEBUG
, "%s", __FUNCTION__
);
324 mlme
.im_op
= IEEE80211_MLME_DISASSOC
;
325 mlme
.im_reason
= reason_code
;
326 os_memcpy(mlme
.im_macaddr
, addr
, IEEE80211_ADDR_LEN
);
327 return set80211priv(drv
, IEEE80211_IOCTL_SETMLME
, &mlme
, sizeof(mlme
), 1);
331 wpa_driver_madwifi_associate(void *priv
,
332 struct wpa_driver_associate_params
*params
)
334 struct wpa_driver_madwifi_data
*drv
= priv
;
335 struct ieee80211req_mlme mlme
;
336 int ret
= 0, privacy
= 1;
338 wpa_printf(MSG_DEBUG
, "%s", __FUNCTION__
);
341 * NB: Don't need to set the freq or cipher-related state as
342 * this is implied by the bssid which is used to locate
343 * the scanned node state which holds it. The ssid is
344 * needed to disambiguate an AP that broadcasts multiple
345 * ssid's but uses the same bssid.
347 /* XXX error handling is wrong but unclear what to do... */
348 if (wpa_driver_madwifi_set_wpa_ie(drv
, params
->wpa_ie
,
349 params
->wpa_ie_len
) < 0)
352 if (params
->pairwise_suite
== CIPHER_NONE
&&
353 params
->group_suite
== CIPHER_NONE
&&
354 params
->key_mgmt_suite
== KEY_MGMT_NONE
&&
355 params
->wpa_ie_len
== 0)
358 if (set80211param(drv
, IEEE80211_PARAM_PRIVACY
, privacy
, 1) < 0)
361 if (params
->wpa_ie_len
&&
362 set80211param(drv
, IEEE80211_PARAM_WPA
,
363 params
->wpa_ie
[0] == WLAN_EID_RSN
? 2 : 1, 1) < 0)
366 if (params
->bssid
== NULL
) {
367 /* ap_scan=2 mode - driver takes care of AP selection and
369 /* FIX: this does not seem to work; would probably need to
370 * change something in the driver */
371 if (set80211param(drv
, IEEE80211_PARAM_ROAMING
, 0, 1) < 0)
374 if (wpa_driver_wext_set_ssid(drv
->wext
, params
->ssid
,
375 params
->ssid_len
) < 0)
378 if (set80211param(drv
, IEEE80211_PARAM_ROAMING
, 2, 1) < 0)
380 if (wpa_driver_wext_set_ssid(drv
->wext
, params
->ssid
,
381 params
->ssid_len
) < 0)
383 os_memset(&mlme
, 0, sizeof(mlme
));
384 mlme
.im_op
= IEEE80211_MLME_ASSOC
;
385 os_memcpy(mlme
.im_macaddr
, params
->bssid
, IEEE80211_ADDR_LEN
);
386 if (set80211priv(drv
, IEEE80211_IOCTL_SETMLME
, &mlme
,
387 sizeof(mlme
), 1) < 0) {
388 wpa_printf(MSG_DEBUG
, "%s: SETMLME[ASSOC] failed",
398 wpa_driver_madwifi_set_auth_alg(void *priv
, int auth_alg
)
400 struct wpa_driver_madwifi_data
*drv
= priv
;
403 if ((auth_alg
& AUTH_ALG_OPEN_SYSTEM
) &&
404 (auth_alg
& AUTH_ALG_SHARED_KEY
))
405 authmode
= IEEE80211_AUTH_AUTO
;
406 else if (auth_alg
& AUTH_ALG_SHARED_KEY
)
407 authmode
= IEEE80211_AUTH_SHARED
;
409 authmode
= IEEE80211_AUTH_OPEN
;
411 return set80211param(drv
, IEEE80211_PARAM_AUTHMODE
, authmode
, 1);
415 wpa_driver_madwifi_scan(void *priv
, const u8
*ssid
, size_t ssid_len
)
417 struct wpa_driver_madwifi_data
*drv
= priv
;
421 os_memset(&iwr
, 0, sizeof(iwr
));
422 os_strlcpy(iwr
.ifr_name
, drv
->ifname
, IFNAMSIZ
);
424 /* set desired ssid before scan */
425 /* FIX: scan should not break the current association, so using
426 * set_ssid may not be the best way of doing this.. */
427 if (wpa_driver_wext_set_ssid(drv
->wext
, ssid
, ssid_len
) < 0)
430 if (ioctl(drv
->sock
, SIOCSIWSCAN
, &iwr
) < 0) {
431 perror("ioctl[SIOCSIWSCAN]");
436 * madwifi delivers a scan complete event so no need to poll, but
437 * register a backup timeout anyway to make sure that we recover even
438 * if the driver does not send this event for any reason. This timeout
439 * will only be used if the event is not delivered (event handler will
440 * cancel the timeout).
442 eloop_cancel_timeout(wpa_driver_wext_scan_timeout
, drv
->wext
,
444 eloop_register_timeout(30, 0, wpa_driver_wext_scan_timeout
, drv
->wext
,
450 static int wpa_driver_madwifi_get_bssid(void *priv
, u8
*bssid
)
452 struct wpa_driver_madwifi_data
*drv
= priv
;
453 return wpa_driver_wext_get_bssid(drv
->wext
, bssid
);
457 static int wpa_driver_madwifi_get_ssid(void *priv
, u8
*ssid
)
459 struct wpa_driver_madwifi_data
*drv
= priv
;
460 return wpa_driver_wext_get_ssid(drv
->wext
, ssid
);
464 static struct wpa_scan_results
*
465 wpa_driver_madwifi_get_scan_results(void *priv
)
467 struct wpa_driver_madwifi_data
*drv
= priv
;
468 return wpa_driver_wext_get_scan_results(drv
->wext
);
472 static int wpa_driver_madwifi_set_operstate(void *priv
, int state
)
474 struct wpa_driver_madwifi_data
*drv
= priv
;
475 return wpa_driver_wext_set_operstate(drv
->wext
, state
);
479 static void * wpa_driver_madwifi_init(void *ctx
, const char *ifname
)
481 struct wpa_driver_madwifi_data
*drv
;
483 drv
= os_zalloc(sizeof(*drv
));
486 drv
->wext
= wpa_driver_wext_init(ctx
, ifname
);
487 if (drv
->wext
== NULL
)
491 os_strlcpy(drv
->ifname
, ifname
, sizeof(drv
->ifname
));
492 drv
->sock
= socket(PF_INET
, SOCK_DGRAM
, 0);
496 if (set80211param(drv
, IEEE80211_PARAM_ROAMING
, 2, 1) < 0) {
497 wpa_printf(MSG_DEBUG
, "%s: failed to set wpa_supplicant-based "
498 "roaming", __FUNCTION__
);
502 if (set80211param(drv
, IEEE80211_PARAM_WPA
, 3, 1) < 0) {
503 wpa_printf(MSG_DEBUG
, "%s: failed to enable WPA support",
513 wpa_driver_wext_deinit(drv
->wext
);
520 static void wpa_driver_madwifi_deinit(void *priv
)
522 struct wpa_driver_madwifi_data
*drv
= priv
;
524 if (wpa_driver_madwifi_set_wpa_ie(drv
, NULL
, 0) < 0) {
525 wpa_printf(MSG_DEBUG
, "%s: failed to clear WPA IE",
528 if (set80211param(drv
, IEEE80211_PARAM_ROAMING
, 0, 1) < 0) {
529 wpa_printf(MSG_DEBUG
, "%s: failed to enable driver-based "
530 "roaming", __FUNCTION__
);
532 if (set80211param(drv
, IEEE80211_PARAM_PRIVACY
, 0, 1) < 0) {
533 wpa_printf(MSG_DEBUG
, "%s: failed to disable forced Privacy "
534 "flag", __FUNCTION__
);
536 if (set80211param(drv
, IEEE80211_PARAM_WPA
, 0, 1) < 0) {
537 wpa_printf(MSG_DEBUG
, "%s: failed to disable WPA",
541 wpa_driver_wext_deinit(drv
->wext
);
548 const struct wpa_driver_ops wpa_driver_madwifi_ops
= {
550 .desc
= "MADWIFI 802.11 support (Atheros, etc.)",
551 .get_bssid
= wpa_driver_madwifi_get_bssid
,
552 .get_ssid
= wpa_driver_madwifi_get_ssid
,
553 .set_key
= wpa_driver_madwifi_set_key
,
554 .init
= wpa_driver_madwifi_init
,
555 .deinit
= wpa_driver_madwifi_deinit
,
556 .set_countermeasures
= wpa_driver_madwifi_set_countermeasures
,
557 .set_drop_unencrypted
= wpa_driver_madwifi_set_drop_unencrypted
,
558 .scan
= wpa_driver_madwifi_scan
,
559 .get_scan_results2
= wpa_driver_madwifi_get_scan_results
,
560 .deauthenticate
= wpa_driver_madwifi_deauthenticate
,
561 .disassociate
= wpa_driver_madwifi_disassociate
,
562 .associate
= wpa_driver_madwifi_associate
,
563 .set_auth_alg
= wpa_driver_madwifi_set_auth_alg
,
564 .set_operstate
= wpa_driver_madwifi_set_operstate
,