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 "wpa_supplicant.h"
25
#include "wireless_copy.h"
27
#include <include/compat.h>
28
#include <net80211/ieee80211.h>
30
/* Assume this is built against BSD branch of madwifi driver. */
32
#include <net80211/_ieee80211.h>
33
#endif /* WME_NUM_AC */
34
#include <net80211/ieee80211_crypto.h>
35
#include <net80211/ieee80211_ioctl.h>
37
#ifdef IEEE80211_IOCTL_SETWMMPARAMS
38
/* Assume this is built against madwifi-ng */
40
#endif /* IEEE80211_IOCTL_SETWMMPARAMS */
42
struct wpa_driver_madwifi_data {
43
void *wext; /* private data for driver_wext */
45
char ifname[IFNAMSIZ + 1];
50
set80211priv(struct wpa_driver_madwifi_data *drv, int op, void *data, int len,
55
os_memset(&iwr, 0, sizeof(iwr));
56
os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
59
* Argument data fits inline; put it there.
61
os_memcpy(iwr.u.name, data, len);
64
* Argument data too big for inline transfer; setup a
65
* parameter block instead; the kernel will transfer
66
* the data for the driver.
68
iwr.u.data.pointer = data;
69
iwr.u.data.length = len;
72
if (ioctl(drv->sock, op, &iwr) < 0) {
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]",
89
"ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
91
"ioctl[IEEE80211_IOCTL_GETCHANINFO]",
92
"ioctl[IEEE80211_IOCTL_SETOPTIE]",
93
"ioctl[IEEE80211_IOCTL_GETOPTIE]",
94
"ioctl[IEEE80211_IOCTL_SETMLME]",
96
"ioctl[IEEE80211_IOCTL_SETKEY]",
98
"ioctl[IEEE80211_IOCTL_DELKEY]",
100
"ioctl[IEEE80211_IOCTL_ADDMAC]",
102
"ioctl[IEEE80211_IOCTL_DELMAC]",
104
"ioctl[IEEE80211_IOCTL_WDSMAC]",
106
"ioctl[IEEE80211_IOCTL_WDSDELMAC]",
108
"ioctl[IEEE80211_IOCTL_KICKMAC]",
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]",
120
"ioctl[IEEE80211_IOCTL_SETMLME]",
122
"ioctl[IEEE80211_IOCTL_SETOPTIE]",
123
"ioctl[IEEE80211_IOCTL_GETOPTIE]",
124
"ioctl[IEEE80211_IOCTL_ADDMAC]",
126
"ioctl[IEEE80211_IOCTL_DELMAC]",
128
"ioctl[IEEE80211_IOCTL_CHANLIST]",
130
#endif /* MADWIFI_NG */
131
int idx = op - first;
132
if (first <= op && op <= last &&
133
idx < (int) (sizeof(opnames) / sizeof(opnames[0]))
135
perror(opnames[idx]);
137
perror("ioctl[unknown???]");
145
set80211param(struct wpa_driver_madwifi_data *drv, int op, int arg,
150
os_memset(&iwr, 0, sizeof(iwr));
151
os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
153
os_memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg));
155
if (ioctl(drv->sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
157
perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
164
wpa_driver_madwifi_set_wpa_ie(struct wpa_driver_madwifi_data *drv,
165
const u8 *wpa_ie, size_t wpa_ie_len)
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;
175
if (ioctl(drv->sock, IEEE80211_IOCTL_SETOPTIE, &iwr) < 0) {
176
perror("ioctl[IEEE80211_IOCTL_SETOPTIE]");
183
wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data *drv, int key_idx,
186
struct ieee80211req_del_key wk;
188
wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __FUNCTION__, key_idx);
189
os_memset(&wk, 0, sizeof(wk));
190
wk.idk_keyix = key_idx;
192
os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
194
return set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk), 1);
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)
203
struct wpa_driver_madwifi_data *drv = priv;
204
struct ieee80211req_key wk;
208
if (alg == WPA_ALG_NONE)
209
return wpa_driver_madwifi_del_key(drv, key_idx, addr);
213
if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
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.
220
return wpa_driver_wext_set_key(drv->wext, alg, addr,
226
cipher = IEEE80211_CIPHER_WEP;
230
cipher = IEEE80211_CIPHER_TKIP;
234
cipher = IEEE80211_CIPHER_AES_CCM;
237
wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
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);
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);
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);
257
os_memset(&wk, 0, sizeof(wk));
259
wk.ik_flags = IEEE80211_KEY_RECV;
261
os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
262
wk.ik_flags |= IEEE80211_KEY_GROUP;
264
wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
265
os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
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
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);
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);
285
return set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk), 1);
289
wpa_driver_madwifi_set_countermeasures(void *priv, int enabled)
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);
298
wpa_driver_madwifi_set_drop_unencrypted(void *priv, int enabled)
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);
306
wpa_driver_madwifi_deauthenticate(void *priv, const u8 *addr, int reason_code)
308
struct wpa_driver_madwifi_data *drv = priv;
309
struct ieee80211req_mlme mlme;
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);
319
wpa_driver_madwifi_disassociate(void *priv, const u8 *addr, int reason_code)
321
struct wpa_driver_madwifi_data *drv = priv;
322
struct ieee80211req_mlme mlme;
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);
332
wpa_driver_madwifi_associate(void *priv,
333
struct wpa_driver_associate_params *params)
335
struct wpa_driver_madwifi_data *drv = priv;
336
struct ieee80211req_mlme mlme;
337
int ret = 0, privacy = 1;
339
wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
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.
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)
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)
359
if (set80211param(drv, IEEE80211_PARAM_PRIVACY, privacy, 1) < 0)
362
if (params->wpa_ie_len &&
363
set80211param(drv, IEEE80211_PARAM_WPA,
364
params->wpa_ie[0] == RSN_INFO_ELEM ? 2 : 1, 1) < 0)
367
if (params->bssid == NULL) {
368
/* ap_scan=2 mode - driver takes care of AP selection and
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)
375
if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
376
params->ssid_len) < 0)
379
if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0)
381
if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
382
params->ssid_len) < 0)
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",
399
wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg)
401
struct wpa_driver_madwifi_data *drv = priv;
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;
410
authmode = IEEE80211_AUTH_OPEN;
412
return set80211param(drv, IEEE80211_PARAM_AUTHMODE, authmode, 1);
416
wpa_driver_madwifi_scan(void *priv, const u8 *ssid, size_t ssid_len)
418
struct wpa_driver_madwifi_data *drv = priv;
422
os_memset(&iwr, 0, sizeof(iwr));
423
os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
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)
431
if (ioctl(drv->sock, SIOCSIWSCAN, &iwr) < 0) {
432
perror("ioctl[SIOCSIWSCAN]");
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).
443
eloop_register_timeout(30, 0, wpa_driver_wext_scan_timeout, drv->wext,
449
static int wpa_driver_madwifi_get_bssid(void *priv, u8 *bssid)
451
struct wpa_driver_madwifi_data *drv = priv;
452
return wpa_driver_wext_get_bssid(drv->wext, bssid);
456
static int wpa_driver_madwifi_get_ssid(void *priv, u8 *ssid)
458
struct wpa_driver_madwifi_data *drv = priv;
459
return wpa_driver_wext_get_ssid(drv->wext, ssid);
463
static int wpa_driver_madwifi_get_scan_results(void *priv,
464
struct wpa_scan_result *results,
467
struct wpa_driver_madwifi_data *drv = priv;
468
return wpa_driver_wext_get_scan_results(drv->wext, results, max_size);
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_strncpy(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_results = 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,