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);
63 op != IEEE80211_IOCTL_SET_APPIEBUF) {
65 * Argument data fits inline; put it there.
67 os_memcpy(iwr.u.name, data, len);
70 * Argument data too big for inline transfer; setup a
71 * parameter block instead; the kernel will transfer
72 * the data for the driver.
74 iwr.u.data.pointer = data;
75 iwr.u.data.length = len;
78 if (ioctl(drv->sock, op, &iwr) < 0) {
81 int first = IEEE80211_IOCTL_SETPARAM;
82 int last = IEEE80211_IOCTL_KICKMAC;
83 static const char *opnames[] = {
84 "ioctl[IEEE80211_IOCTL_SETPARAM]",
85 "ioctl[IEEE80211_IOCTL_GETPARAM]",
86 "ioctl[IEEE80211_IOCTL_SETMODE]",
87 "ioctl[IEEE80211_IOCTL_GETMODE]",
88 "ioctl[IEEE80211_IOCTL_SETWMMPARAMS]",
89 "ioctl[IEEE80211_IOCTL_GETWMMPARAMS]",
90 "ioctl[IEEE80211_IOCTL_SETCHANLIST]",
91 "ioctl[IEEE80211_IOCTL_GETCHANLIST]",
92 "ioctl[IEEE80211_IOCTL_CHANSWITCH]",
94 "ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
95 "ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
97 "ioctl[IEEE80211_IOCTL_GETCHANINFO]",
98 "ioctl[IEEE80211_IOCTL_SETOPTIE]",
99 "ioctl[IEEE80211_IOCTL_GETOPTIE]",
100 "ioctl[IEEE80211_IOCTL_SETMLME]",
102 "ioctl[IEEE80211_IOCTL_SETKEY]",
104 "ioctl[IEEE80211_IOCTL_DELKEY]",
106 "ioctl[IEEE80211_IOCTL_ADDMAC]",
108 "ioctl[IEEE80211_IOCTL_DELMAC]",
110 "ioctl[IEEE80211_IOCTL_WDSMAC]",
112 "ioctl[IEEE80211_IOCTL_WDSDELMAC]",
114 "ioctl[IEEE80211_IOCTL_KICKMAC]",
116 #else /* MADWIFI_NG */
117 int first = IEEE80211_IOCTL_SETPARAM;
118 int last = IEEE80211_IOCTL_CHANLIST;
119 static const char *opnames[] = {
120 "ioctl[IEEE80211_IOCTL_SETPARAM]",
121 "ioctl[IEEE80211_IOCTL_GETPARAM]",
122 "ioctl[IEEE80211_IOCTL_SETKEY]",
123 "ioctl[IEEE80211_IOCTL_GETKEY]",
124 "ioctl[IEEE80211_IOCTL_DELKEY]",
126 "ioctl[IEEE80211_IOCTL_SETMLME]",
128 "ioctl[IEEE80211_IOCTL_SETOPTIE]",
129 "ioctl[IEEE80211_IOCTL_GETOPTIE]",
130 "ioctl[IEEE80211_IOCTL_ADDMAC]",
132 "ioctl[IEEE80211_IOCTL_DELMAC]",
134 "ioctl[IEEE80211_IOCTL_CHANLIST]",
136 #endif /* MADWIFI_NG */
137 int idx = op - first;
138 if (first <= op && op <= last &&
139 idx < (int) (sizeof(opnames) / sizeof(opnames[0]))
141 perror(opnames[idx]);
143 perror("ioctl[unknown???]");
151 set80211param(struct wpa_driver_madwifi_data *drv, int op, int arg,
156 os_memset(&iwr, 0, sizeof(iwr));
157 os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
159 os_memcpy(iwr.u.name+sizeof(u32), &arg, sizeof(arg));
161 if (ioctl(drv->sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
163 perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
170 wpa_driver_madwifi_set_wpa_ie(struct wpa_driver_madwifi_data *drv,
171 const u8 *wpa_ie, size_t wpa_ie_len)
175 os_memset(&iwr, 0, sizeof(iwr));
176 os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
177 /* NB: SETOPTIE is not fixed-size so must not be inlined */
178 iwr.u.data.pointer = (void *) wpa_ie;
179 iwr.u.data.length = wpa_ie_len;
181 if (ioctl(drv->sock, IEEE80211_IOCTL_SETOPTIE, &iwr) < 0) {
182 perror("ioctl[IEEE80211_IOCTL_SETOPTIE]");
189 wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data *drv, int key_idx,
192 struct ieee80211req_del_key wk;
194 wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __FUNCTION__, key_idx);
195 os_memset(&wk, 0, sizeof(wk));
196 wk.idk_keyix = key_idx;
198 os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
200 return set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk), 1);
204 wpa_driver_madwifi_set_key(void *priv, wpa_alg alg,
205 const u8 *addr, int key_idx, int set_tx,
206 const u8 *seq, size_t seq_len,
207 const u8 *key, size_t key_len)
209 struct wpa_driver_madwifi_data *drv = priv;
210 struct ieee80211req_key wk;
214 if (alg == WPA_ALG_NONE)
215 return wpa_driver_madwifi_del_key(drv, key_idx, addr);
219 if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
222 * madwifi did not seem to like static WEP key
223 * configuration with IEEE80211_IOCTL_SETKEY, so use
224 * Linux wireless extensions ioctl for this.
226 return wpa_driver_wext_set_key(drv->wext, alg, addr,
232 cipher = IEEE80211_CIPHER_WEP;
236 cipher = IEEE80211_CIPHER_TKIP;
240 cipher = IEEE80211_CIPHER_AES_CCM;
243 wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
248 wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
249 "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
250 (unsigned long) seq_len, (unsigned long) key_len);
252 if (seq_len > sizeof(u_int64_t)) {
253 wpa_printf(MSG_DEBUG, "%s: seq_len %lu too big",
254 __FUNCTION__, (unsigned long) seq_len);
257 if (key_len > sizeof(wk.ik_keydata)) {
258 wpa_printf(MSG_DEBUG, "%s: key length %lu too big",
259 __FUNCTION__, (unsigned long) key_len);
263 os_memset(&wk, 0, sizeof(wk));
265 wk.ik_flags = IEEE80211_KEY_RECV;
267 os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
268 wk.ik_flags |= IEEE80211_KEY_GROUP;
270 wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
271 os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
273 os_memset(wk.ik_macaddr, 0, IEEE80211_ADDR_LEN);
274 wk.ik_keyix = key_idx;
275 wk.ik_keylen = key_len;
276 #ifdef WORDS_BIGENDIAN
277 #define WPA_KEY_RSC_LEN 8
280 u8 tmp[WPA_KEY_RSC_LEN];
281 os_memset(tmp, 0, sizeof(tmp));
282 for (i = 0; i < seq_len; i++)
283 tmp[WPA_KEY_RSC_LEN - i - 1] = seq[i];
284 os_memcpy(&wk.ik_keyrsc, tmp, WPA_KEY_RSC_LEN);
286 #else /* WORDS_BIGENDIAN */
287 os_memcpy(&wk.ik_keyrsc, seq, seq_len);
288 #endif /* WORDS_BIGENDIAN */
289 os_memcpy(wk.ik_keydata, key, key_len);
291 return set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk), 1);
295 wpa_driver_madwifi_set_countermeasures(void *priv, int enabled)
297 struct wpa_driver_madwifi_data *drv = priv;
298 wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
299 return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled, 1);
304 wpa_driver_madwifi_set_drop_unencrypted(void *priv, int enabled)
306 struct wpa_driver_madwifi_data *drv = priv;
307 wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
308 return set80211param(drv, IEEE80211_PARAM_DROPUNENCRYPTED, enabled, 1);
312 wpa_driver_madwifi_deauthenticate(void *priv, const u8 *addr, int reason_code)
314 struct wpa_driver_madwifi_data *drv = priv;
315 struct ieee80211req_mlme mlme;
317 wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
318 mlme.im_op = IEEE80211_MLME_DEAUTH;
319 mlme.im_reason = reason_code;
320 os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
321 return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
325 wpa_driver_madwifi_disassociate(void *priv, const u8 *addr, int reason_code)
327 struct wpa_driver_madwifi_data *drv = priv;
328 struct ieee80211req_mlme mlme;
330 wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
331 mlme.im_op = IEEE80211_MLME_DISASSOC;
332 mlme.im_reason = reason_code;
333 os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
334 return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
338 wpa_driver_madwifi_associate(void *priv,
339 struct wpa_driver_associate_params *params)
341 struct wpa_driver_madwifi_data *drv = priv;
342 struct ieee80211req_mlme mlme;
343 int ret = 0, privacy = 1;
345 wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
348 * NB: Don't need to set the freq or cipher-related state as
349 * this is implied by the bssid which is used to locate
350 * the scanned node state which holds it. The ssid is
351 * needed to disambiguate an AP that broadcasts multiple
352 * ssid's but uses the same bssid.
354 /* XXX error handling is wrong but unclear what to do... */
355 if (wpa_driver_madwifi_set_wpa_ie(drv, params->wpa_ie,
356 params->wpa_ie_len) < 0)
359 if (params->pairwise_suite == CIPHER_NONE &&
360 params->group_suite == CIPHER_NONE &&
361 params->key_mgmt_suite == KEY_MGMT_NONE &&
362 params->wpa_ie_len == 0)
365 if (set80211param(drv, IEEE80211_PARAM_PRIVACY, privacy, 1) < 0)
368 if (params->wpa_ie_len &&
369 set80211param(drv, IEEE80211_PARAM_WPA,
370 params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1, 1) < 0)
373 if (params->bssid == NULL) {
374 /* ap_scan=2 mode - driver takes care of AP selection and
376 /* FIX: this does not seem to work; would probably need to
377 * change something in the driver */
378 if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0)
381 if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
382 params->ssid_len) < 0)
385 if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0)
387 if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
388 params->ssid_len) < 0)
390 os_memset(&mlme, 0, sizeof(mlme));
391 mlme.im_op = IEEE80211_MLME_ASSOC;
392 os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
393 if (set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
394 sizeof(mlme), 1) < 0) {
395 wpa_printf(MSG_DEBUG, "%s: SETMLME[ASSOC] failed",
405 wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg)
407 struct wpa_driver_madwifi_data *drv = priv;
410 if ((auth_alg & AUTH_ALG_OPEN_SYSTEM) &&
411 (auth_alg & AUTH_ALG_SHARED_KEY))
412 authmode = IEEE80211_AUTH_AUTO;
413 else if (auth_alg & AUTH_ALG_SHARED_KEY)
414 authmode = IEEE80211_AUTH_SHARED;
416 authmode = IEEE80211_AUTH_OPEN;
418 return set80211param(drv, IEEE80211_PARAM_AUTHMODE, authmode, 1);
422 wpa_driver_madwifi_scan(void *priv, const u8 *ssid, size_t ssid_len)
424 struct wpa_driver_madwifi_data *drv = priv;
428 os_memset(&iwr, 0, sizeof(iwr));
429 os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
431 /* set desired ssid before scan */
432 /* FIX: scan should not break the current association, so using
433 * set_ssid may not be the best way of doing this.. */
434 if (wpa_driver_wext_set_ssid(drv->wext, ssid, ssid_len) < 0)
437 if (ioctl(drv->sock, SIOCSIWSCAN, &iwr) < 0) {
438 perror("ioctl[SIOCSIWSCAN]");
443 * madwifi delivers a scan complete event so no need to poll, but
444 * register a backup timeout anyway to make sure that we recover even
445 * if the driver does not send this event for any reason. This timeout
446 * will only be used if the event is not delivered (event handler will
447 * cancel the timeout).
449 eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
451 eloop_register_timeout(30, 0, wpa_driver_wext_scan_timeout, drv->wext,
457 static int wpa_driver_madwifi_get_bssid(void *priv, u8 *bssid)
459 struct wpa_driver_madwifi_data *drv = priv;
460 return wpa_driver_wext_get_bssid(drv->wext, bssid);
464 static int wpa_driver_madwifi_get_ssid(void *priv, u8 *ssid)
466 struct wpa_driver_madwifi_data *drv = priv;
467 return wpa_driver_wext_get_ssid(drv->wext, ssid);
471 static struct wpa_scan_results *
472 wpa_driver_madwifi_get_scan_results(void *priv)
474 struct wpa_driver_madwifi_data *drv = priv;
475 return wpa_driver_wext_get_scan_results(drv->wext);
479 static int wpa_driver_madwifi_set_operstate(void *priv, int state)
481 struct wpa_driver_madwifi_data *drv = priv;
482 return wpa_driver_wext_set_operstate(drv->wext, state);
486 static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies,
489 struct ieee80211req_getset_appiebuf *probe_req_ie;
492 probe_req_ie = os_malloc(sizeof(*probe_req_ie) + ies_len);
493 if (probe_req_ie == NULL)
496 probe_req_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_REQ;
497 probe_req_ie->app_buflen = ies_len;
498 os_memcpy(probe_req_ie->app_buf, ies, ies_len);
500 ret = set80211priv(priv, IEEE80211_IOCTL_SET_APPIEBUF, probe_req_ie,
501 sizeof(struct ieee80211req_getset_appiebuf) +
504 os_free(probe_req_ie);
510 static void * wpa_driver_madwifi_init(void *ctx, const char *ifname)
512 struct wpa_driver_madwifi_data *drv;
514 drv = os_zalloc(sizeof(*drv));
517 drv->wext = wpa_driver_wext_init(ctx, ifname);
518 if (drv->wext == NULL)
522 os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
523 drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
527 if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0) {
528 wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
529 "roaming", __FUNCTION__);
533 if (set80211param(drv, IEEE80211_PARAM_WPA, 3, 1) < 0) {
534 wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support",
544 wpa_driver_wext_deinit(drv->wext);
551 static void wpa_driver_madwifi_deinit(void *priv)
553 struct wpa_driver_madwifi_data *drv = priv;
555 if (wpa_driver_madwifi_set_wpa_ie(drv, NULL, 0) < 0) {
556 wpa_printf(MSG_DEBUG, "%s: failed to clear WPA IE",
559 if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0) {
560 wpa_printf(MSG_DEBUG, "%s: failed to enable driver-based "
561 "roaming", __FUNCTION__);
563 if (set80211param(drv, IEEE80211_PARAM_PRIVACY, 0, 1) < 0) {
564 wpa_printf(MSG_DEBUG, "%s: failed to disable forced Privacy "
565 "flag", __FUNCTION__);
567 if (set80211param(drv, IEEE80211_PARAM_WPA, 0, 1) < 0) {
568 wpa_printf(MSG_DEBUG, "%s: failed to disable WPA",
572 wpa_driver_wext_deinit(drv->wext);
579 const struct wpa_driver_ops wpa_driver_madwifi_ops = {
581 .desc = "MADWIFI 802.11 support (Atheros, etc.)",
582 .get_bssid = wpa_driver_madwifi_get_bssid,
583 .get_ssid = wpa_driver_madwifi_get_ssid,
584 .set_key = wpa_driver_madwifi_set_key,
585 .init = wpa_driver_madwifi_init,
586 .deinit = wpa_driver_madwifi_deinit,
587 .set_countermeasures = wpa_driver_madwifi_set_countermeasures,
588 .set_drop_unencrypted = wpa_driver_madwifi_set_drop_unencrypted,
589 .scan = wpa_driver_madwifi_scan,
590 .get_scan_results2 = wpa_driver_madwifi_get_scan_results,
591 .deauthenticate = wpa_driver_madwifi_deauthenticate,
592 .disassociate = wpa_driver_madwifi_disassociate,
593 .associate = wpa_driver_madwifi_associate,
594 .set_auth_alg = wpa_driver_madwifi_set_auth_alg,
595 .set_operstate = wpa_driver_madwifi_set_operstate,
596 .set_probe_req_ie = wpa_driver_madwifi_set_probe_req_ie,