Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / wpa / src / drivers / driver_madwifi.c
blobaeabe34c563adc8bde594ce385a7cd767abe634b
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>
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
11 * license.
13 * See README and COPYING for more details.
16 #include "includes.h"
17 #include <sys/ioctl.h>
19 #include "common.h"
20 #include "driver.h"
21 #include "driver_wext.h"
22 #include "eloop.h"
23 #include "ieee802_11_defs.h"
24 #include "wireless_copy.h"
26 #include <include/compat.h>
27 #include <net80211/ieee80211.h>
28 #ifdef WME_NUM_AC
29 /* Assume this is built against BSD branch of madwifi driver. */
30 #define MADWIFI_BSD
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 */
38 #define MADWIFI_NG
39 #endif /* IEEE80211_IOCTL_SETWMMPARAMS */
41 struct wpa_driver_madwifi_data {
42 void *wext; /* private data for driver_wext */
43 void *ctx;
44 char ifname[IFNAMSIZ + 1];
45 int sock;
48 static int
49 set80211priv(struct wpa_driver_madwifi_data *drv, int op, void *data, int len,
50 int show_err)
52 struct iwreq iwr;
54 os_memset(&iwr, 0, sizeof(iwr));
55 os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
56 if (len < IFNAMSIZ) {
58 * Argument data fits inline; put it there.
60 os_memcpy(iwr.u.name, data, len);
61 } else {
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) {
72 if (show_err) {
73 #ifdef MADWIFI_NG
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]",
86 NULL,
87 NULL,
88 "ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
89 NULL,
90 "ioctl[IEEE80211_IOCTL_GETCHANINFO]",
91 "ioctl[IEEE80211_IOCTL_SETOPTIE]",
92 "ioctl[IEEE80211_IOCTL_GETOPTIE]",
93 "ioctl[IEEE80211_IOCTL_SETMLME]",
94 NULL,
95 "ioctl[IEEE80211_IOCTL_SETKEY]",
96 NULL,
97 "ioctl[IEEE80211_IOCTL_DELKEY]",
98 NULL,
99 "ioctl[IEEE80211_IOCTL_ADDMAC]",
100 NULL,
101 "ioctl[IEEE80211_IOCTL_DELMAC]",
102 NULL,
103 "ioctl[IEEE80211_IOCTL_WDSMAC]",
104 NULL,
105 "ioctl[IEEE80211_IOCTL_WDSDELMAC]",
106 NULL,
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]",
118 NULL,
119 "ioctl[IEEE80211_IOCTL_SETMLME]",
120 NULL,
121 "ioctl[IEEE80211_IOCTL_SETOPTIE]",
122 "ioctl[IEEE80211_IOCTL_GETOPTIE]",
123 "ioctl[IEEE80211_IOCTL_ADDMAC]",
124 NULL,
125 "ioctl[IEEE80211_IOCTL_DELMAC]",
126 NULL,
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]))
133 && opnames[idx])
134 perror(opnames[idx]);
135 else
136 perror("ioctl[unknown???]");
138 return -1;
140 return 0;
143 static int
144 set80211param(struct wpa_driver_madwifi_data *drv, int op, int arg,
145 int show_err)
147 struct iwreq iwr;
149 os_memset(&iwr, 0, sizeof(iwr));
150 os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
151 iwr.u.mode = op;
152 os_memcpy(iwr.u.name+sizeof(u32), &arg, sizeof(arg));
154 if (ioctl(drv->sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
155 if (show_err)
156 perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
157 return -1;
159 return 0;
162 static int
163 wpa_driver_madwifi_set_wpa_ie(struct wpa_driver_madwifi_data *drv,
164 const u8 *wpa_ie, size_t wpa_ie_len)
166 struct iwreq iwr;
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]");
176 return -1;
178 return 0;
181 static int
182 wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data *drv, int key_idx,
183 const u8 *addr)
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;
190 if (addr != NULL)
191 os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
193 return set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk), 1);
196 static int
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;
204 char *alg_name;
205 u_int8_t cipher;
207 if (alg == WPA_ALG_NONE)
208 return wpa_driver_madwifi_del_key(drv, key_idx, addr);
210 switch (alg) {
211 case WPA_ALG_WEP:
212 if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
213 ETH_ALEN) == 0) {
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,
220 key_idx, set_tx,
221 seq, seq_len,
222 key, key_len);
224 alg_name = "WEP";
225 cipher = IEEE80211_CIPHER_WEP;
226 break;
227 case WPA_ALG_TKIP:
228 alg_name = "TKIP";
229 cipher = IEEE80211_CIPHER_TKIP;
230 break;
231 case WPA_ALG_CCMP:
232 alg_name = "CCMP";
233 cipher = IEEE80211_CIPHER_AES_CCM;
234 break;
235 default:
236 wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
237 __FUNCTION__, alg);
238 return -1;
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);
248 return -2;
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);
253 return -3;
256 os_memset(&wk, 0, sizeof(wk));
257 wk.ik_type = cipher;
258 wk.ik_flags = IEEE80211_KEY_RECV;
259 if (addr == NULL ||
260 os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
261 wk.ik_flags |= IEEE80211_KEY_GROUP;
262 if (set_tx) {
263 wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
264 os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
265 } else
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
272 size_t i;
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);
287 static int
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);
296 static int
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);
304 static int
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);
317 static int
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);
330 static int
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)
350 ret = -1;
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)
356 privacy = 0;
358 if (set80211param(drv, IEEE80211_PARAM_PRIVACY, privacy, 1) < 0)
359 ret = -1;
361 if (params->wpa_ie_len &&
362 set80211param(drv, IEEE80211_PARAM_WPA,
363 params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1, 1) < 0)
364 ret = -1;
366 if (params->bssid == NULL) {
367 /* ap_scan=2 mode - driver takes care of AP selection and
368 * roaming */
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)
372 ret = -1;
374 if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
375 params->ssid_len) < 0)
376 ret = -1;
377 } else {
378 if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0)
379 ret = -1;
380 if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
381 params->ssid_len) < 0)
382 ret = -1;
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",
389 __func__);
390 ret = -1;
394 return ret;
397 static int
398 wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg)
400 struct wpa_driver_madwifi_data *drv = priv;
401 int authmode;
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;
408 else
409 authmode = IEEE80211_AUTH_OPEN;
411 return set80211param(drv, IEEE80211_PARAM_AUTHMODE, authmode, 1);
414 static int
415 wpa_driver_madwifi_scan(void *priv, const u8 *ssid, size_t ssid_len)
417 struct wpa_driver_madwifi_data *drv = priv;
418 struct iwreq iwr;
419 int ret = 0;
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)
428 ret = -1;
430 if (ioctl(drv->sock, SIOCSIWSCAN, &iwr) < 0) {
431 perror("ioctl[SIOCSIWSCAN]");
432 ret = -1;
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,
443 drv->ctx);
444 eloop_register_timeout(30, 0, wpa_driver_wext_scan_timeout, drv->wext,
445 drv->ctx);
447 return ret;
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));
484 if (drv == NULL)
485 return NULL;
486 drv->wext = wpa_driver_wext_init(ctx, ifname);
487 if (drv->wext == NULL)
488 goto fail;
490 drv->ctx = ctx;
491 os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
492 drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
493 if (drv->sock < 0)
494 goto fail2;
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__);
499 goto fail3;
502 if (set80211param(drv, IEEE80211_PARAM_WPA, 3, 1) < 0) {
503 wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support",
504 __FUNCTION__);
505 goto fail3;
508 return drv;
510 fail3:
511 close(drv->sock);
512 fail2:
513 wpa_driver_wext_deinit(drv->wext);
514 fail:
515 os_free(drv);
516 return NULL;
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",
526 __FUNCTION__);
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",
538 __FUNCTION__);
541 wpa_driver_wext_deinit(drv->wext);
543 close(drv->sock);
544 os_free(drv);
548 const struct wpa_driver_ops wpa_driver_madwifi_ops = {
549 .name = "madwifi",
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,