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"
27 * Avoid conflicts with wpa_supplicant definitions by undefining a definition.
31 #include <include/compat.h>
32 #include <net80211/ieee80211.h>
34 /* Assume this is built against BSD branch of madwifi driver. */
36 #include <net80211/_ieee80211.h>
37 #endif /* WME_NUM_AC */
38 #include <net80211/ieee80211_crypto.h>
39 #include <net80211/ieee80211_ioctl.h>
42 #ifdef IEEE80211_IOCTL_SETWMMPARAMS
43 /* Assume this is built against madwifi-ng */
45 #endif /* IEEE80211_IOCTL_SETWMMPARAMS */
47 struct wpa_driver_madwifi_data {
48 void *wext; /* private data for driver_wext */
50 char ifname[IFNAMSIZ + 1];
55 set80211priv(struct wpa_driver_madwifi_data *drv, int op, void *data, int len,
60 os_memset(&iwr, 0, sizeof(iwr));
61 os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
64 * Argument data fits inline; put it there.
66 os_memcpy(iwr.u.name, data, len);
69 * Argument data too big for inline transfer; setup a
70 * parameter block instead; the kernel will transfer
71 * the data for the driver.
73 iwr.u.data.pointer = data;
74 iwr.u.data.length = len;
77 if (ioctl(drv->sock, op, &iwr) < 0) {
80 int first = IEEE80211_IOCTL_SETPARAM;
81 int last = IEEE80211_IOCTL_KICKMAC;
82 static const char *opnames[] = {
83 "ioctl[IEEE80211_IOCTL_SETPARAM]",
84 "ioctl[IEEE80211_IOCTL_GETPARAM]",
85 "ioctl[IEEE80211_IOCTL_SETMODE]",
86 "ioctl[IEEE80211_IOCTL_GETMODE]",
87 "ioctl[IEEE80211_IOCTL_SETWMMPARAMS]",
88 "ioctl[IEEE80211_IOCTL_GETWMMPARAMS]",
89 "ioctl[IEEE80211_IOCTL_SETCHANLIST]",
90 "ioctl[IEEE80211_IOCTL_GETCHANLIST]",
91 "ioctl[IEEE80211_IOCTL_CHANSWITCH]",
94 "ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
96 "ioctl[IEEE80211_IOCTL_GETCHANINFO]",
97 "ioctl[IEEE80211_IOCTL_SETOPTIE]",
98 "ioctl[IEEE80211_IOCTL_GETOPTIE]",
99 "ioctl[IEEE80211_IOCTL_SETMLME]",
101 "ioctl[IEEE80211_IOCTL_SETKEY]",
103 "ioctl[IEEE80211_IOCTL_DELKEY]",
105 "ioctl[IEEE80211_IOCTL_ADDMAC]",
107 "ioctl[IEEE80211_IOCTL_DELMAC]",
109 "ioctl[IEEE80211_IOCTL_WDSMAC]",
111 "ioctl[IEEE80211_IOCTL_WDSDELMAC]",
113 "ioctl[IEEE80211_IOCTL_KICKMAC]",
115 #else /* MADWIFI_NG */
116 int first = IEEE80211_IOCTL_SETPARAM;
117 int last = IEEE80211_IOCTL_CHANLIST;
118 static const char *opnames[] = {
119 "ioctl[IEEE80211_IOCTL_SETPARAM]",
120 "ioctl[IEEE80211_IOCTL_GETPARAM]",
121 "ioctl[IEEE80211_IOCTL_SETKEY]",
122 "ioctl[IEEE80211_IOCTL_GETKEY]",
123 "ioctl[IEEE80211_IOCTL_DELKEY]",
125 "ioctl[IEEE80211_IOCTL_SETMLME]",
127 "ioctl[IEEE80211_IOCTL_SETOPTIE]",
128 "ioctl[IEEE80211_IOCTL_GETOPTIE]",
129 "ioctl[IEEE80211_IOCTL_ADDMAC]",
131 "ioctl[IEEE80211_IOCTL_DELMAC]",
133 "ioctl[IEEE80211_IOCTL_CHANLIST]",
135 #endif /* MADWIFI_NG */
136 int idx = op - first;
137 if (first <= op && op <= last &&
138 idx < (int) (sizeof(opnames) / sizeof(opnames[0]))
140 perror(opnames[idx]);
142 perror("ioctl[unknown???]");
150 set80211param(struct wpa_driver_madwifi_data *drv, int op, int arg,
155 os_memset(&iwr, 0, sizeof(iwr));
156 os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
158 os_memcpy(iwr.u.name+sizeof(u32), &arg, sizeof(arg));
160 if (ioctl(drv->sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
162 perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
169 wpa_driver_madwifi_set_wpa_ie(struct wpa_driver_madwifi_data *drv,
170 const u8 *wpa_ie, size_t wpa_ie_len)
174 os_memset(&iwr, 0, sizeof(iwr));
175 os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
176 /* NB: SETOPTIE is not fixed-size so must not be inlined */
177 iwr.u.data.pointer = (void *) wpa_ie;
178 iwr.u.data.length = wpa_ie_len;
180 if (ioctl(drv->sock, IEEE80211_IOCTL_SETOPTIE, &iwr) < 0) {
181 perror("ioctl[IEEE80211_IOCTL_SETOPTIE]");
188 wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data *drv, int key_idx,
191 struct ieee80211req_del_key wk;
193 wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __FUNCTION__, key_idx);
194 os_memset(&wk, 0, sizeof(wk));
195 wk.idk_keyix = key_idx;
197 os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
199 return set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk), 1);
203 wpa_driver_madwifi_set_key(void *priv, wpa_alg alg,
204 const u8 *addr, int key_idx, int set_tx,
205 const u8 *seq, size_t seq_len,
206 const u8 *key, size_t key_len)
208 struct wpa_driver_madwifi_data *drv = priv;
209 struct ieee80211req_key wk;
213 if (alg == WPA_ALG_NONE)
214 return wpa_driver_madwifi_del_key(drv, key_idx, addr);
218 if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
221 * madwifi did not seem to like static WEP key
222 * configuration with IEEE80211_IOCTL_SETKEY, so use
223 * Linux wireless extensions ioctl for this.
225 return wpa_driver_wext_set_key(drv->wext, alg, addr,
231 cipher = IEEE80211_CIPHER_WEP;
235 cipher = IEEE80211_CIPHER_TKIP;
239 cipher = IEEE80211_CIPHER_AES_CCM;
242 wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
247 wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
248 "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
249 (unsigned long) seq_len, (unsigned long) key_len);
251 if (seq_len > sizeof(u_int64_t)) {
252 wpa_printf(MSG_DEBUG, "%s: seq_len %lu too big",
253 __FUNCTION__, (unsigned long) seq_len);
256 if (key_len > sizeof(wk.ik_keydata)) {
257 wpa_printf(MSG_DEBUG, "%s: key length %lu too big",
258 __FUNCTION__, (unsigned long) key_len);
262 os_memset(&wk, 0, sizeof(wk));
264 wk.ik_flags = IEEE80211_KEY_RECV;
266 os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
267 wk.ik_flags |= IEEE80211_KEY_GROUP;
269 wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
270 os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
272 os_memset(wk.ik_macaddr, 0, IEEE80211_ADDR_LEN);
273 wk.ik_keyix = key_idx;
274 wk.ik_keylen = key_len;
275 #ifdef WORDS_BIGENDIAN
276 #define WPA_KEY_RSC_LEN 8
279 u8 tmp[WPA_KEY_RSC_LEN];
280 os_memset(tmp, 0, sizeof(tmp));
281 for (i = 0; i < seq_len; i++)
282 tmp[WPA_KEY_RSC_LEN - i - 1] = seq[i];
283 os_memcpy(&wk.ik_keyrsc, tmp, WPA_KEY_RSC_LEN);
285 #else /* WORDS_BIGENDIAN */
286 os_memcpy(&wk.ik_keyrsc, seq, seq_len);
287 #endif /* WORDS_BIGENDIAN */
288 os_memcpy(wk.ik_keydata, key, key_len);
290 return set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk), 1);
294 wpa_driver_madwifi_set_countermeasures(void *priv, int enabled)
296 struct wpa_driver_madwifi_data *drv = priv;
297 wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
298 return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled, 1);
303 wpa_driver_madwifi_set_drop_unencrypted(void *priv, int enabled)
305 struct wpa_driver_madwifi_data *drv = priv;
306 wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
307 return set80211param(drv, IEEE80211_PARAM_DROPUNENCRYPTED, enabled, 1);
311 wpa_driver_madwifi_deauthenticate(void *priv, const u8 *addr, int reason_code)
313 struct wpa_driver_madwifi_data *drv = priv;
314 struct ieee80211req_mlme mlme;
316 wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
317 mlme.im_op = IEEE80211_MLME_DEAUTH;
318 mlme.im_reason = reason_code;
319 os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
320 return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
324 wpa_driver_madwifi_disassociate(void *priv, const u8 *addr, int reason_code)
326 struct wpa_driver_madwifi_data *drv = priv;
327 struct ieee80211req_mlme mlme;
329 wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
330 mlme.im_op = IEEE80211_MLME_DISASSOC;
331 mlme.im_reason = reason_code;
332 os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
333 return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
337 wpa_driver_madwifi_associate(void *priv,
338 struct wpa_driver_associate_params *params)
340 struct wpa_driver_madwifi_data *drv = priv;
341 struct ieee80211req_mlme mlme;
342 int ret = 0, privacy = 1;
344 wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
347 * NB: Don't need to set the freq or cipher-related state as
348 * this is implied by the bssid which is used to locate
349 * the scanned node state which holds it. The ssid is
350 * needed to disambiguate an AP that broadcasts multiple
351 * ssid's but uses the same bssid.
353 /* XXX error handling is wrong but unclear what to do... */
354 if (wpa_driver_madwifi_set_wpa_ie(drv, params->wpa_ie,
355 params->wpa_ie_len) < 0)
358 if (params->pairwise_suite == CIPHER_NONE &&
359 params->group_suite == CIPHER_NONE &&
360 params->key_mgmt_suite == KEY_MGMT_NONE &&
361 params->wpa_ie_len == 0)
364 if (set80211param(drv, IEEE80211_PARAM_PRIVACY, privacy, 1) < 0)
367 if (params->wpa_ie_len &&
368 set80211param(drv, IEEE80211_PARAM_WPA,
369 params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1, 1) < 0)
372 if (params->bssid == NULL) {
373 /* ap_scan=2 mode - driver takes care of AP selection and
375 /* FIX: this does not seem to work; would probably need to
376 * change something in the driver */
377 if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0)
380 if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
381 params->ssid_len) < 0)
384 if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0)
386 if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
387 params->ssid_len) < 0)
389 os_memset(&mlme, 0, sizeof(mlme));
390 mlme.im_op = IEEE80211_MLME_ASSOC;
391 os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
392 if (set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
393 sizeof(mlme), 1) < 0) {
394 wpa_printf(MSG_DEBUG, "%s: SETMLME[ASSOC] failed",
404 wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg)
406 struct wpa_driver_madwifi_data *drv = priv;
409 if ((auth_alg & AUTH_ALG_OPEN_SYSTEM) &&
410 (auth_alg & AUTH_ALG_SHARED_KEY))
411 authmode = IEEE80211_AUTH_AUTO;
412 else if (auth_alg & AUTH_ALG_SHARED_KEY)
413 authmode = IEEE80211_AUTH_SHARED;
415 authmode = IEEE80211_AUTH_OPEN;
417 return set80211param(drv, IEEE80211_PARAM_AUTHMODE, authmode, 1);
421 wpa_driver_madwifi_scan(void *priv, const u8 *ssid, size_t ssid_len)
423 struct wpa_driver_madwifi_data *drv = priv;
427 os_memset(&iwr, 0, sizeof(iwr));
428 os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
430 /* set desired ssid before scan */
431 /* FIX: scan should not break the current association, so using
432 * set_ssid may not be the best way of doing this.. */
433 if (wpa_driver_wext_set_ssid(drv->wext, ssid, ssid_len) < 0)
436 if (ioctl(drv->sock, SIOCSIWSCAN, &iwr) < 0) {
437 perror("ioctl[SIOCSIWSCAN]");
442 * madwifi delivers a scan complete event so no need to poll, but
443 * register a backup timeout anyway to make sure that we recover even
444 * if the driver does not send this event for any reason. This timeout
445 * will only be used if the event is not delivered (event handler will
446 * cancel the timeout).
448 eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
450 eloop_register_timeout(30, 0, wpa_driver_wext_scan_timeout, drv->wext,
456 static int wpa_driver_madwifi_get_bssid(void *priv, u8 *bssid)
458 struct wpa_driver_madwifi_data *drv = priv;
459 return wpa_driver_wext_get_bssid(drv->wext, bssid);
463 static int wpa_driver_madwifi_get_ssid(void *priv, u8 *ssid)
465 struct wpa_driver_madwifi_data *drv = priv;
466 return wpa_driver_wext_get_ssid(drv->wext, ssid);
470 static struct wpa_scan_results *
471 wpa_driver_madwifi_get_scan_results(void *priv)
473 struct wpa_driver_madwifi_data *drv = priv;
474 return wpa_driver_wext_get_scan_results(drv->wext);
478 static int wpa_driver_madwifi_set_operstate(void *priv, int state)
480 struct wpa_driver_madwifi_data *drv = priv;
481 return wpa_driver_wext_set_operstate(drv->wext, state);
485 static void * wpa_driver_madwifi_init(void *ctx, const char *ifname)
487 struct wpa_driver_madwifi_data *drv;
489 drv = os_zalloc(sizeof(*drv));
492 drv->wext = wpa_driver_wext_init(ctx, ifname);
493 if (drv->wext == NULL)
497 os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
498 drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
502 if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0) {
503 wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
504 "roaming", __FUNCTION__);
508 if (set80211param(drv, IEEE80211_PARAM_WPA, 3, 1) < 0) {
509 wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support",
519 wpa_driver_wext_deinit(drv->wext);
526 static void wpa_driver_madwifi_deinit(void *priv)
528 struct wpa_driver_madwifi_data *drv = priv;
530 if (wpa_driver_madwifi_set_wpa_ie(drv, NULL, 0) < 0) {
531 wpa_printf(MSG_DEBUG, "%s: failed to clear WPA IE",
534 if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0) {
535 wpa_printf(MSG_DEBUG, "%s: failed to enable driver-based "
536 "roaming", __FUNCTION__);
538 if (set80211param(drv, IEEE80211_PARAM_PRIVACY, 0, 1) < 0) {
539 wpa_printf(MSG_DEBUG, "%s: failed to disable forced Privacy "
540 "flag", __FUNCTION__);
542 if (set80211param(drv, IEEE80211_PARAM_WPA, 0, 1) < 0) {
543 wpa_printf(MSG_DEBUG, "%s: failed to disable WPA",
547 wpa_driver_wext_deinit(drv->wext);
554 const struct wpa_driver_ops wpa_driver_madwifi_ops = {
556 .desc = "MADWIFI 802.11 support (Atheros, etc.)",
557 .get_bssid = wpa_driver_madwifi_get_bssid,
558 .get_ssid = wpa_driver_madwifi_get_ssid,
559 .set_key = wpa_driver_madwifi_set_key,
560 .init = wpa_driver_madwifi_init,
561 .deinit = wpa_driver_madwifi_deinit,
562 .set_countermeasures = wpa_driver_madwifi_set_countermeasures,
563 .set_drop_unencrypted = wpa_driver_madwifi_set_drop_unencrypted,
564 .scan = wpa_driver_madwifi_scan,
565 .get_scan_results2 = wpa_driver_madwifi_get_scan_results,
566 .deauthenticate = wpa_driver_madwifi_deauthenticate,
567 .disassociate = wpa_driver_madwifi_disassociate,
568 .associate = wpa_driver_madwifi_associate,
569 .set_auth_alg = wpa_driver_madwifi_set_auth_alg,
570 .set_operstate = wpa_driver_madwifi_set_operstate,