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>
5 *
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.
9 *
10 * Alternatively, this software may be distributed under the terms of BSD
11 * license.
12 *
13 * See README and COPYING for more details.
14 */
15
16#include "includes.h"
17#include <sys/ioctl.h>
18
19#include "common.h"
20#include "driver.h"
21#include "driver_wext.h"
22#include "eloop.h"
23#include "wpa_supplicant.h"
24#include "wpa.h"
25#include "wireless_copy.h"
26
27#include <include/compat.h>
28#include <net80211/ieee80211.h>
29#ifdef WME_NUM_AC
30/* Assume this is built against BSD branch of madwifi driver. */
31#define MADWIFI_BSD
32#include <net80211/_ieee80211.h>
33#endif /* WME_NUM_AC */
34#include <net80211/ieee80211_crypto.h>
35#include <net80211/ieee80211_ioctl.h>
36
37#ifdef IEEE80211_IOCTL_SETWMMPARAMS
38/* Assume this is built against madwifi-ng */
39#define MADWIFI_NG
40#endif /* IEEE80211_IOCTL_SETWMMPARAMS */
41
42struct wpa_driver_madwifi_data {
43	void *wext; /* private data for driver_wext */
44	void *ctx;
45	char ifname[IFNAMSIZ + 1];
46	int sock;
47};
48
49static int
50set80211priv(struct wpa_driver_madwifi_data *drv, int op, void *data, int len,
51	     int show_err)
52{
53	struct iwreq iwr;
54
55	os_memset(&iwr, 0, sizeof(iwr));
56	os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
57	if (len < IFNAMSIZ) {
58		/*
59		 * Argument data fits inline; put it there.
60		 */
61		os_memcpy(iwr.u.name, data, len);
62	} else {
63		/*
64		 * Argument data too big for inline transfer; setup a
65		 * parameter block instead; the kernel will transfer
66		 * the data for the driver.
67		 */
68		iwr.u.data.pointer = data;
69		iwr.u.data.length = len;
70	}
71
72	if (ioctl(drv->sock, op, &iwr) < 0) {
73		if (show_err) {
74#ifdef MADWIFI_NG
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]",
87				NULL,
88				NULL,
89				"ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
90				NULL,
91				"ioctl[IEEE80211_IOCTL_GETCHANINFO]",
92				"ioctl[IEEE80211_IOCTL_SETOPTIE]",
93				"ioctl[IEEE80211_IOCTL_GETOPTIE]",
94				"ioctl[IEEE80211_IOCTL_SETMLME]",
95				NULL,
96				"ioctl[IEEE80211_IOCTL_SETKEY]",
97				NULL,
98				"ioctl[IEEE80211_IOCTL_DELKEY]",
99				NULL,
100				"ioctl[IEEE80211_IOCTL_ADDMAC]",
101				NULL,
102				"ioctl[IEEE80211_IOCTL_DELMAC]",
103				NULL,
104				"ioctl[IEEE80211_IOCTL_WDSMAC]",
105				NULL,
106				"ioctl[IEEE80211_IOCTL_WDSDELMAC]",
107				NULL,
108				"ioctl[IEEE80211_IOCTL_KICKMAC]",
109			};
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]",
119				NULL,
120				"ioctl[IEEE80211_IOCTL_SETMLME]",
121				NULL,
122				"ioctl[IEEE80211_IOCTL_SETOPTIE]",
123				"ioctl[IEEE80211_IOCTL_GETOPTIE]",
124				"ioctl[IEEE80211_IOCTL_ADDMAC]",
125				NULL,
126				"ioctl[IEEE80211_IOCTL_DELMAC]",
127				NULL,
128				"ioctl[IEEE80211_IOCTL_CHANLIST]",
129			};
130#endif /* MADWIFI_NG */
131			int idx = op - first;
132			if (first <= op && op <= last &&
133			    idx < (int) (sizeof(opnames) / sizeof(opnames[0]))
134			    && opnames[idx])
135				perror(opnames[idx]);
136			else
137				perror("ioctl[unknown???]");
138		}
139		return -1;
140	}
141	return 0;
142}
143
144static int
145set80211param(struct wpa_driver_madwifi_data *drv, int op, int arg,
146	      int show_err)
147{
148	struct iwreq iwr;
149
150	os_memset(&iwr, 0, sizeof(iwr));
151	os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
152	iwr.u.mode = op;
153	os_memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg));
154
155	if (ioctl(drv->sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
156		if (show_err)
157			perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
158		return -1;
159	}
160	return 0;
161}
162
163static int
164wpa_driver_madwifi_set_wpa_ie(struct wpa_driver_madwifi_data *drv,
165			      const u8 *wpa_ie, size_t wpa_ie_len)
166{
167	struct iwreq iwr;
168
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;
174
175	if (ioctl(drv->sock, IEEE80211_IOCTL_SETOPTIE, &iwr) < 0) {
176		perror("ioctl[IEEE80211_IOCTL_SETOPTIE]");
177		return -1;
178	}
179	return 0;
180}
181
182static int
183wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data *drv, int key_idx,
184			   const u8 *addr)
185{
186	struct ieee80211req_del_key wk;
187
188	wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __FUNCTION__, key_idx);
189	os_memset(&wk, 0, sizeof(wk));
190	wk.idk_keyix = key_idx;
191	if (addr != NULL)
192		os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
193
194	return set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk), 1);
195}
196
197static int
198wpa_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)
202{
203	struct wpa_driver_madwifi_data *drv = priv;
204	struct ieee80211req_key wk;
205	char *alg_name;
206	u_int8_t cipher;
207
208	if (alg == WPA_ALG_NONE)
209		return wpa_driver_madwifi_del_key(drv, key_idx, addr);
210
211	switch (alg) {
212	case WPA_ALG_WEP:
213		if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
214					      ETH_ALEN) == 0) {
215			/*
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.
219			 */
220			return wpa_driver_wext_set_key(drv->wext, alg, addr,
221						       key_idx, set_tx,
222						       seq, seq_len,
223						       key, key_len);
224		}
225		alg_name = "WEP";
226		cipher = IEEE80211_CIPHER_WEP;
227		break;
228	case WPA_ALG_TKIP:
229		alg_name = "TKIP";
230		cipher = IEEE80211_CIPHER_TKIP;
231		break;
232	case WPA_ALG_CCMP:
233		alg_name = "CCMP";
234		cipher = IEEE80211_CIPHER_AES_CCM;
235		break;
236	default:
237		wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
238			__FUNCTION__, alg);
239		return -1;
240	}
241
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);
245
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);
249		return -2;
250	}
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);
254		return -3;
255	}
256
257	os_memset(&wk, 0, sizeof(wk));
258	wk.ik_type = cipher;
259	wk.ik_flags = IEEE80211_KEY_RECV;
260	if (addr == NULL ||
261	    os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
262		wk.ik_flags |= IEEE80211_KEY_GROUP;
263	if (set_tx) {
264		wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
265		os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
266	} else
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
272	{
273		size_t i;
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);
279	}
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);
284
285	return set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk), 1);
286}
287
288static int
289wpa_driver_madwifi_set_countermeasures(void *priv, int enabled)
290{
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);
294}
295
296
297static int
298wpa_driver_madwifi_set_drop_unencrypted(void *priv, int enabled)
299{
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);
303}
304
305static int
306wpa_driver_madwifi_deauthenticate(void *priv, const u8 *addr, int reason_code)
307{
308	struct wpa_driver_madwifi_data *drv = priv;
309	struct ieee80211req_mlme mlme;
310
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);
316}
317
318static int
319wpa_driver_madwifi_disassociate(void *priv, const u8 *addr, int reason_code)
320{
321	struct wpa_driver_madwifi_data *drv = priv;
322	struct ieee80211req_mlme mlme;
323
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);
329}
330
331static int
332wpa_driver_madwifi_associate(void *priv,
333			     struct wpa_driver_associate_params *params)
334{
335	struct wpa_driver_madwifi_data *drv = priv;
336	struct ieee80211req_mlme mlme;
337	int ret = 0, privacy = 1;
338
339	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
340
341	/*
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.
347	 */
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)
351		ret = -1;
352
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)
357		privacy = 0;
358
359	if (set80211param(drv, IEEE80211_PARAM_PRIVACY, privacy, 1) < 0)
360		ret = -1;
361
362	if (params->wpa_ie_len &&
363	    set80211param(drv, IEEE80211_PARAM_WPA,
364			  params->wpa_ie[0] == RSN_INFO_ELEM ? 2 : 1, 1) < 0)
365		ret = -1;
366
367	if (params->bssid == NULL) {
368		/* ap_scan=2 mode - driver takes care of AP selection and
369		 * roaming */
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)
373			ret = -1;
374
375		if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
376					     params->ssid_len) < 0)
377			ret = -1;
378	} else {
379		if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0)
380			ret = -1;
381		if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
382					     params->ssid_len) < 0)
383			ret = -1;
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",
390				   __func__);
391			ret = -1;
392		}
393	}
394
395	return ret;
396}
397
398static int
399wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg)
400{
401	struct wpa_driver_madwifi_data *drv = priv;
402	int authmode;
403
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;
409	else
410		authmode = IEEE80211_AUTH_OPEN;
411
412	return set80211param(drv, IEEE80211_PARAM_AUTHMODE, authmode, 1);
413}
414
415static int
416wpa_driver_madwifi_scan(void *priv, const u8 *ssid, size_t ssid_len)
417{
418	struct wpa_driver_madwifi_data *drv = priv;
419	struct iwreq iwr;
420	int ret = 0;
421
422	os_memset(&iwr, 0, sizeof(iwr));
423	os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
424
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)
429		ret = -1;
430
431	if (ioctl(drv->sock, SIOCSIWSCAN, &iwr) < 0) {
432		perror("ioctl[SIOCSIWSCAN]");
433		ret = -1;
434	}
435
436	/*
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).
442	 */
443	eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
444			     drv->ctx);
445	eloop_register_timeout(30, 0, wpa_driver_wext_scan_timeout, drv->wext,
446			       drv->ctx);
447
448	return ret;
449}
450
451static int wpa_driver_madwifi_get_bssid(void *priv, u8 *bssid)
452{
453	struct wpa_driver_madwifi_data *drv = priv;
454	return wpa_driver_wext_get_bssid(drv->wext, bssid);
455}
456
457
458static int wpa_driver_madwifi_get_ssid(void *priv, u8 *ssid)
459{
460	struct wpa_driver_madwifi_data *drv = priv;
461	return wpa_driver_wext_get_ssid(drv->wext, ssid);
462}
463
464
465static int wpa_driver_madwifi_get_scan_results(void *priv,
466					    struct wpa_scan_result *results,
467					    size_t max_size)
468{
469	struct wpa_driver_madwifi_data *drv = priv;
470	return wpa_driver_wext_get_scan_results(drv->wext, results, max_size);
471}
472
473
474static int wpa_driver_madwifi_set_operstate(void *priv, int state)
475{
476	struct wpa_driver_madwifi_data *drv = priv;
477	return wpa_driver_wext_set_operstate(drv->wext, state);
478}
479
480
481static void * wpa_driver_madwifi_init(void *ctx, const char *ifname)
482{
483	struct wpa_driver_madwifi_data *drv;
484
485	drv = os_zalloc(sizeof(*drv));
486	if (drv == NULL)
487		return NULL;
488	drv->wext = wpa_driver_wext_init(ctx, ifname);
489	if (drv->wext == NULL)
490		goto fail;
491
492	drv->ctx = ctx;
493	os_strncpy(drv->ifname, ifname, sizeof(drv->ifname));
494	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
495	if (drv->sock < 0)
496		goto fail2;
497
498	if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0) {
499		wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
500			   "roaming", __FUNCTION__);
501		goto fail3;
502	}
503
504	if (set80211param(drv, IEEE80211_PARAM_WPA, 3, 1) < 0) {
505		wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support",
506			   __FUNCTION__);
507		goto fail3;
508	}
509
510	return drv;
511
512fail3:
513	close(drv->sock);
514fail2:
515	wpa_driver_wext_deinit(drv->wext);
516fail:
517	os_free(drv);
518	return NULL;
519}
520
521
522static void wpa_driver_madwifi_deinit(void *priv)
523{
524	struct wpa_driver_madwifi_data *drv = priv;
525
526	if (wpa_driver_madwifi_set_wpa_ie(drv, NULL, 0) < 0) {
527		wpa_printf(MSG_DEBUG, "%s: failed to clear WPA IE",
528			   __FUNCTION__);
529	}
530	if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0) {
531		wpa_printf(MSG_DEBUG, "%s: failed to enable driver-based "
532			   "roaming", __FUNCTION__);
533	}
534	if (set80211param(drv, IEEE80211_PARAM_PRIVACY, 0, 1) < 0) {
535		wpa_printf(MSG_DEBUG, "%s: failed to disable forced Privacy "
536			   "flag", __FUNCTION__);
537	}
538	if (set80211param(drv, IEEE80211_PARAM_WPA, 0, 1) < 0) {
539		wpa_printf(MSG_DEBUG, "%s: failed to disable WPA",
540			   __FUNCTION__);
541	}
542
543	wpa_driver_wext_deinit(drv->wext);
544
545	close(drv->sock);
546	os_free(drv);
547}
548
549
550const struct wpa_driver_ops wpa_driver_madwifi_ops = {
551	.name			= "madwifi",
552	.desc			= "MADWIFI 802.11 support (Atheros, etc.)",
553	.get_bssid		= wpa_driver_madwifi_get_bssid,
554	.get_ssid		= wpa_driver_madwifi_get_ssid,
555	.set_key		= wpa_driver_madwifi_set_key,
556	.init			= wpa_driver_madwifi_init,
557	.deinit			= wpa_driver_madwifi_deinit,
558	.set_countermeasures	= wpa_driver_madwifi_set_countermeasures,
559	.set_drop_unencrypted	= wpa_driver_madwifi_set_drop_unencrypted,
560	.scan			= wpa_driver_madwifi_scan,
561	.get_scan_results	= wpa_driver_madwifi_get_scan_results,
562	.deauthenticate		= wpa_driver_madwifi_deauthenticate,
563	.disassociate		= wpa_driver_madwifi_disassociate,
564	.associate		= wpa_driver_madwifi_associate,
565	.set_auth_alg		= wpa_driver_madwifi_set_auth_alg,
566	.set_operstate		= wpa_driver_madwifi_set_operstate,
567};
568