blob: 2547a43d7a91ed6c983a4a91f3ee9d2339fa3bd9 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd / Driver interaction with Atheros driver
3 * Copyright (c) 2004, Sam Leffler <sam@errno.com>
4 * Copyright (c) 2004, Video54 Technologies
5 * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
6 * Copyright (c) 2009, Atheros Communications
7 *
Dmitry Shmidt04949592012-07-19 12:16:46 -07008 * This software may be distributed under the terms of the BSD license.
9 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070010 */
11
12#include "includes.h"
13#include <net/if.h>
14#include <sys/ioctl.h>
15
16#include "common.h"
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070017#include "eloop.h"
18#include "common/ieee802_11_defs.h"
19#include "l2_packet/l2_packet.h"
20#include "p2p/p2p.h"
21
22#include "common.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070023#ifndef _BYTE_ORDER
24#ifdef WORDS_BIGENDIAN
25#define _BYTE_ORDER _BIG_ENDIAN
26#else
27#define _BYTE_ORDER _LITTLE_ENDIAN
28#endif
29#endif /* _BYTE_ORDER */
30
31/*
32 * Note, the ATH_WPS_IE setting must match with the driver build.. If the
33 * driver does not include this, the IEEE80211_IOCTL_GETWPAIE ioctl will fail.
34 */
35#define ATH_WPS_IE
36
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080037#include "ieee80211_external.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070038
39
40#ifdef CONFIG_WPS
41#include <netpacket/packet.h>
Dmitry Shmidt04949592012-07-19 12:16:46 -070042#endif /* CONFIG_WPS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070043
44#ifndef ETH_P_80211_RAW
45#define ETH_P_80211_RAW 0x0019
46#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070047
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080048#include "linux_wext.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070049
50#include "driver.h"
51#include "eloop.h"
52#include "priv_netlink.h"
53#include "l2_packet/l2_packet.h"
54#include "common/ieee802_11_defs.h"
55#include "netlink.h"
56#include "linux_ioctl.h"
57
58
59struct atheros_driver_data {
60 struct hostapd_data *hapd; /* back pointer */
61
62 char iface[IFNAMSIZ + 1];
63 int ifindex;
64 struct l2_packet_data *sock_xmit; /* raw packet xmit socket */
65 struct l2_packet_data *sock_recv; /* raw packet recv socket */
66 int ioctl_sock; /* socket for ioctl() use */
67 struct netlink_data *netlink;
68 int we_version;
69 u8 acct_mac[ETH_ALEN];
70 struct hostap_sta_driver_data acct_data;
71
72 struct l2_packet_data *sock_raw; /* raw 802.11 management frames */
73 struct wpabuf *wpa_ie;
74 struct wpabuf *wps_beacon_ie;
75 struct wpabuf *wps_probe_resp_ie;
Dmitry Shmidt04949592012-07-19 12:16:46 -070076 u8 own_addr[ETH_ALEN];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070077};
78
79static int atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
80 int reason_code);
81static int atheros_set_privacy(void *priv, int enabled);
82
83static const char * athr_get_ioctl_name(int op)
84{
85 switch (op) {
86 case IEEE80211_IOCTL_SETPARAM:
87 return "SETPARAM";
88 case IEEE80211_IOCTL_GETPARAM:
89 return "GETPARAM";
90 case IEEE80211_IOCTL_SETKEY:
91 return "SETKEY";
92 case IEEE80211_IOCTL_SETWMMPARAMS:
93 return "SETWMMPARAMS";
94 case IEEE80211_IOCTL_DELKEY:
95 return "DELKEY";
96 case IEEE80211_IOCTL_GETWMMPARAMS:
97 return "GETWMMPARAMS";
98 case IEEE80211_IOCTL_SETMLME:
99 return "SETMLME";
100 case IEEE80211_IOCTL_GETCHANINFO:
101 return "GETCHANINFO";
102 case IEEE80211_IOCTL_SETOPTIE:
103 return "SETOPTIE";
104 case IEEE80211_IOCTL_GETOPTIE:
105 return "GETOPTIE";
106 case IEEE80211_IOCTL_ADDMAC:
107 return "ADDMAC";
108 case IEEE80211_IOCTL_DELMAC:
109 return "DELMAC";
110 case IEEE80211_IOCTL_GETCHANLIST:
111 return "GETCHANLIST";
112 case IEEE80211_IOCTL_SETCHANLIST:
113 return "SETCHANLIST";
114 case IEEE80211_IOCTL_KICKMAC:
115 return "KICKMAC";
116 case IEEE80211_IOCTL_CHANSWITCH:
117 return "CHANSWITCH";
118 case IEEE80211_IOCTL_GETMODE:
119 return "GETMODE";
120 case IEEE80211_IOCTL_SETMODE:
121 return "SETMODE";
122 case IEEE80211_IOCTL_GET_APPIEBUF:
123 return "GET_APPIEBUF";
124 case IEEE80211_IOCTL_SET_APPIEBUF:
125 return "SET_APPIEBUF";
126 case IEEE80211_IOCTL_SET_ACPARAMS:
127 return "SET_ACPARAMS";
128 case IEEE80211_IOCTL_FILTERFRAME:
129 return "FILTERFRAME";
130 case IEEE80211_IOCTL_SET_RTPARAMS:
131 return "SET_RTPARAMS";
132 case IEEE80211_IOCTL_SET_MEDENYENTRY:
133 return "SET_MEDENYENTRY";
134 case IEEE80211_IOCTL_GET_MACADDR:
135 return "GET_MACADDR";
136 case IEEE80211_IOCTL_SET_HBRPARAMS:
137 return "SET_HBRPARAMS";
138 case IEEE80211_IOCTL_SET_RXTIMEOUT:
139 return "SET_RXTIMEOUT";
140 case IEEE80211_IOCTL_STA_STATS:
141 return "STA_STATS";
142 case IEEE80211_IOCTL_GETWPAIE:
143 return "GETWPAIE";
144 default:
145 return "??";
146 }
147}
148
149
150static const char * athr_get_param_name(int op)
151{
152 switch (op) {
153 case IEEE80211_IOC_MCASTCIPHER:
154 return "MCASTCIPHER";
155 case IEEE80211_PARAM_MCASTKEYLEN:
156 return "MCASTKEYLEN";
157 case IEEE80211_PARAM_UCASTCIPHERS:
158 return "UCASTCIPHERS";
159 case IEEE80211_PARAM_KEYMGTALGS:
160 return "KEYMGTALGS";
161 case IEEE80211_PARAM_RSNCAPS:
162 return "RSNCAPS";
163 case IEEE80211_PARAM_WPA:
164 return "WPA";
165 case IEEE80211_PARAM_AUTHMODE:
166 return "AUTHMODE";
167 case IEEE80211_PARAM_PRIVACY:
168 return "PRIVACY";
169 case IEEE80211_PARAM_COUNTERMEASURES:
170 return "COUNTERMEASURES";
171 default:
172 return "??";
173 }
174}
175
176
177static int
178set80211priv(struct atheros_driver_data *drv, int op, void *data, int len)
179{
180 struct iwreq iwr;
181 int do_inline = len < IFNAMSIZ;
182
183 /* Certain ioctls must use the non-inlined method */
184 if (op == IEEE80211_IOCTL_SET_APPIEBUF ||
185 op == IEEE80211_IOCTL_FILTERFRAME)
186 do_inline = 0;
187
188 memset(&iwr, 0, sizeof(iwr));
189 os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
190 if (do_inline) {
191 /*
192 * Argument data fits inline; put it there.
193 */
194 memcpy(iwr.u.name, data, len);
195 } else {
196 /*
197 * Argument data too big for inline transfer; setup a
198 * parameter block instead; the kernel will transfer
199 * the data for the driver.
200 */
201 iwr.u.data.pointer = data;
202 iwr.u.data.length = len;
203 }
204
205 if (ioctl(drv->ioctl_sock, op, &iwr) < 0) {
206 wpa_printf(MSG_DEBUG, "atheros: %s: %s: ioctl op=0x%x "
207 "(%s) len=%d failed: %d (%s)",
208 __func__, drv->iface, op,
209 athr_get_ioctl_name(op),
210 len, errno, strerror(errno));
211 return -1;
212 }
213 return 0;
214}
215
216static int
217set80211param(struct atheros_driver_data *drv, int op, int arg)
218{
219 struct iwreq iwr;
220
221 memset(&iwr, 0, sizeof(iwr));
222 os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
223 iwr.u.mode = op;
224 memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg));
225
226 if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
227 perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
228 wpa_printf(MSG_DEBUG, "%s: %s: Failed to set parameter (op %d "
229 "(%s) arg %d)", __func__, drv->iface, op,
230 athr_get_param_name(op), arg);
231 return -1;
232 }
233 return 0;
234}
235
236#ifndef CONFIG_NO_STDOUT_DEBUG
237static const char *
238ether_sprintf(const u8 *addr)
239{
240 static char buf[sizeof(MACSTR)];
241
242 if (addr != NULL)
243 snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
244 else
245 snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
246 return buf;
247}
248#endif /* CONFIG_NO_STDOUT_DEBUG */
249
250/*
251 * Configure WPA parameters.
252 */
253static int
254atheros_configure_wpa(struct atheros_driver_data *drv,
255 struct wpa_bss_params *params)
256{
257 int v;
258
259 switch (params->wpa_group) {
260 case WPA_CIPHER_CCMP:
261 v = IEEE80211_CIPHER_AES_CCM;
262 break;
263 case WPA_CIPHER_TKIP:
264 v = IEEE80211_CIPHER_TKIP;
265 break;
266 case WPA_CIPHER_WEP104:
267 v = IEEE80211_CIPHER_WEP;
268 break;
269 case WPA_CIPHER_WEP40:
270 v = IEEE80211_CIPHER_WEP;
271 break;
272 case WPA_CIPHER_NONE:
273 v = IEEE80211_CIPHER_NONE;
274 break;
275 default:
276 wpa_printf(MSG_ERROR, "Unknown group key cipher %u",
277 params->wpa_group);
278 return -1;
279 }
280 wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v);
281 if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) {
282 printf("Unable to set group key cipher to %u\n", v);
283 return -1;
284 }
285 if (v == IEEE80211_CIPHER_WEP) {
286 /* key length is done only for specific ciphers */
287 v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
288 if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) {
289 printf("Unable to set group key length to %u\n", v);
290 return -1;
291 }
292 }
293
294 v = 0;
295 if (params->wpa_pairwise & WPA_CIPHER_CCMP)
296 v |= 1<<IEEE80211_CIPHER_AES_CCM;
297 if (params->wpa_pairwise & WPA_CIPHER_TKIP)
298 v |= 1<<IEEE80211_CIPHER_TKIP;
299 if (params->wpa_pairwise & WPA_CIPHER_NONE)
300 v |= 1<<IEEE80211_CIPHER_NONE;
301 wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
302 if (set80211param(drv, IEEE80211_PARAM_UCASTCIPHERS, v)) {
303 printf("Unable to set pairwise key ciphers to 0x%x\n", v);
304 return -1;
305 }
306
307 wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
308 __func__, params->wpa_key_mgmt);
309 if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS,
310 params->wpa_key_mgmt)) {
311 printf("Unable to set key management algorithms to 0x%x\n",
312 params->wpa_key_mgmt);
313 return -1;
314 }
315
316 v = 0;
317 if (params->rsn_preauth)
318 v |= BIT(0);
319#ifdef CONFIG_IEEE80211W
320 if (params->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
321 v |= BIT(7);
322 if (params->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
323 v |= BIT(6);
324 }
325#endif /* CONFIG_IEEE80211W */
326
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700327 wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", __func__, v);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700328 if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
329 printf("Unable to set RSN capabilities to 0x%x\n", v);
330 return -1;
331 }
332
333 wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa);
334 if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) {
335 printf("Unable to set WPA to %u\n", params->wpa);
336 return -1;
337 }
338 return 0;
339}
340
341static int
342atheros_set_ieee8021x(void *priv, struct wpa_bss_params *params)
343{
344 struct atheros_driver_data *drv = priv;
345
346 wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled);
347
348 if (!params->enabled) {
349 /* XXX restore state */
350 if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
351 IEEE80211_AUTH_AUTO) < 0)
352 return -1;
353 /* IEEE80211_AUTH_AUTO ends up enabling Privacy; clear that */
354 return atheros_set_privacy(drv, 0);
355 }
356 if (!params->wpa && !params->ieee802_1x) {
357 hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
358 HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!");
359 return -1;
360 }
361 if (params->wpa && atheros_configure_wpa(drv, params) != 0) {
362 hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
363 HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!");
364 return -1;
365 }
366 if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
367 (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
368 hostapd_logger(drv->hapd, NULL, HOSTAPD_MODULE_DRIVER,
369 HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!");
370 return -1;
371 }
372
373 return 0;
374}
375
376static int
377atheros_set_privacy(void *priv, int enabled)
378{
379 struct atheros_driver_data *drv = priv;
380
381 wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
382
383 return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled);
384}
385
386static int
387atheros_set_sta_authorized(void *priv, const u8 *addr, int authorized)
388{
389 struct atheros_driver_data *drv = priv;
390 struct ieee80211req_mlme mlme;
391 int ret;
392
393 wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d",
394 __func__, ether_sprintf(addr), authorized);
395
396 if (authorized)
397 mlme.im_op = IEEE80211_MLME_AUTHORIZE;
398 else
399 mlme.im_op = IEEE80211_MLME_UNAUTHORIZE;
400 mlme.im_reason = 0;
401 memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
402 ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
403 if (ret < 0) {
404 wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR,
405 __func__, authorized ? "" : "un", MAC2STR(addr));
406 }
407
408 return ret;
409}
410
411static int
412atheros_sta_set_flags(void *priv, const u8 *addr,
413 int total_flags, int flags_or, int flags_and)
414{
415 /* For now, only support setting Authorized flag */
416 if (flags_or & WPA_STA_AUTHORIZED)
417 return atheros_set_sta_authorized(priv, addr, 1);
418 if (!(flags_and & WPA_STA_AUTHORIZED))
419 return atheros_set_sta_authorized(priv, addr, 0);
420 return 0;
421}
422
423static int
424atheros_del_key(void *priv, const u8 *addr, int key_idx)
425{
426 struct atheros_driver_data *drv = priv;
427 struct ieee80211req_del_key wk;
428 int ret;
429
430 wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d",
431 __func__, ether_sprintf(addr), key_idx);
432
433 memset(&wk, 0, sizeof(wk));
434 if (addr != NULL) {
435 memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
436 wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE;
437 } else {
438 wk.idk_keyix = key_idx;
439 }
440
441 ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk));
442 if (ret < 0) {
443 wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s"
444 " key_idx %d)", __func__, ether_sprintf(addr),
445 key_idx);
446 }
447
448 return ret;
449}
450
451static int
452atheros_set_key(const char *ifname, void *priv, enum wpa_alg alg,
453 const u8 *addr, int key_idx, int set_tx, const u8 *seq,
454 size_t seq_len, const u8 *key, size_t key_len)
455{
456 struct atheros_driver_data *drv = priv;
457 struct ieee80211req_key wk;
458 u_int8_t cipher;
459 int ret;
460
461 if (alg == WPA_ALG_NONE)
462 return atheros_del_key(drv, addr, key_idx);
463
464 wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d",
465 __func__, alg, ether_sprintf(addr), key_idx);
466
467 switch (alg) {
468 case WPA_ALG_WEP:
469 cipher = IEEE80211_CIPHER_WEP;
470 break;
471 case WPA_ALG_TKIP:
472 cipher = IEEE80211_CIPHER_TKIP;
473 break;
474 case WPA_ALG_CCMP:
475 cipher = IEEE80211_CIPHER_AES_CCM;
476 break;
477#ifdef CONFIG_IEEE80211W
478 case WPA_ALG_IGTK:
479 cipher = IEEE80211_CIPHER_AES_CMAC;
480 break;
481#endif /* CONFIG_IEEE80211W */
482 default:
483 printf("%s: unknown/unsupported algorithm %d\n",
484 __func__, alg);
485 return -1;
486 }
487
488 if (key_len > sizeof(wk.ik_keydata)) {
489 printf("%s: key length %lu too big\n", __func__,
490 (unsigned long) key_len);
491 return -3;
492 }
493
494 memset(&wk, 0, sizeof(wk));
495 wk.ik_type = cipher;
496 wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT;
497 if (addr == NULL || is_broadcast_ether_addr(addr)) {
498 memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
499 wk.ik_keyix = key_idx;
500 if (set_tx)
501 wk.ik_flags |= IEEE80211_KEY_DEFAULT;
502 } else {
503 memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
504 wk.ik_keyix = IEEE80211_KEYIX_NONE;
505 }
506 wk.ik_keylen = key_len;
507 memcpy(wk.ik_keydata, key, key_len);
508
509 ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk));
510 if (ret < 0) {
511 wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s"
512 " key_idx %d alg %d key_len %lu set_tx %d)",
513 __func__, ether_sprintf(wk.ik_macaddr), key_idx,
514 alg, (unsigned long) key_len, set_tx);
515 }
516
517 return ret;
518}
519
520
521static int
522atheros_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
523 u8 *seq)
524{
525 struct atheros_driver_data *drv = priv;
526 struct ieee80211req_key wk;
527
528 wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
529 __func__, ether_sprintf(addr), idx);
530
531 memset(&wk, 0, sizeof(wk));
532 if (addr == NULL)
533 memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
534 else
535 memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
536 wk.ik_keyix = idx;
537
538 if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) {
539 wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data "
540 "(addr " MACSTR " key_idx %d)",
541 __func__, MAC2STR(wk.ik_macaddr), idx);
542 return -1;
543 }
544
545#ifdef WORDS_BIGENDIAN
546 {
547 /*
548 * wk.ik_keytsc is in host byte order (big endian), need to
549 * swap it to match with the byte order used in WPA.
550 */
551 int i;
552#ifndef WPA_KEY_RSC_LEN
553#define WPA_KEY_RSC_LEN 8
554#endif
555 u8 tmp[WPA_KEY_RSC_LEN];
556 memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
557 for (i = 0; i < WPA_KEY_RSC_LEN; i++) {
558 seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1];
559 }
560 }
561#else /* WORDS_BIGENDIAN */
562 memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
563#endif /* WORDS_BIGENDIAN */
564 return 0;
565}
566
567
568static int
569atheros_flush(void *priv)
570{
571 u8 allsta[IEEE80211_ADDR_LEN];
572 memset(allsta, 0xff, IEEE80211_ADDR_LEN);
573 return atheros_sta_deauth(priv, NULL, allsta,
574 IEEE80211_REASON_AUTH_LEAVE);
575}
576
577
578static int
579atheros_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
580 const u8 *addr)
581{
582 struct atheros_driver_data *drv = priv;
583 struct ieee80211req_sta_stats stats;
584
585 memset(data, 0, sizeof(*data));
586
587 /*
588 * Fetch statistics for station from the system.
589 */
590 memset(&stats, 0, sizeof(stats));
591 memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);
592 if (set80211priv(drv, IEEE80211_IOCTL_STA_STATS,
593 &stats, sizeof(stats))) {
594 wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr "
595 MACSTR ")", __func__, MAC2STR(addr));
596 if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
597 memcpy(data, &drv->acct_data, sizeof(*data));
598 return 0;
599 }
600
601 printf("Failed to get station stats information element.\n");
602 return -1;
603 }
604
605 data->rx_packets = stats.is_stats.ns_rx_data;
606 data->rx_bytes = stats.is_stats.ns_rx_bytes;
607 data->tx_packets = stats.is_stats.ns_tx_data;
608 data->tx_bytes = stats.is_stats.ns_tx_bytes;
609 return 0;
610}
611
612
613static int
614atheros_sta_clear_stats(void *priv, const u8 *addr)
615{
616 struct atheros_driver_data *drv = priv;
617 struct ieee80211req_mlme mlme;
618 int ret;
619
620 wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr));
621
622 mlme.im_op = IEEE80211_MLME_CLEAR_STATS;
623 memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
624 ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
625 sizeof(mlme));
626 if (ret < 0) {
627 wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr "
628 MACSTR ")", __func__, MAC2STR(addr));
629 }
630
631 return ret;
632}
633
634
635static int
636atheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
637{
638 struct atheros_driver_data *drv = priv;
639 u8 buf[512];
640 struct ieee80211req_getset_appiebuf *app_ie;
641
642 wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
643 (unsigned long) ie_len);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800644 wpa_hexdump(MSG_DEBUG, "atheros: set_generic_elem", ie, ie_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700645
646 wpabuf_free(drv->wpa_ie);
647 drv->wpa_ie = wpabuf_alloc_copy(ie, ie_len);
648
649 app_ie = (struct ieee80211req_getset_appiebuf *) buf;
650 os_memcpy(&(app_ie->app_buf[0]), ie, ie_len);
651 app_ie->app_buflen = ie_len;
652
653 app_ie->app_frmtype = IEEE80211_APPIE_FRAME_BEACON;
654
655 /* append WPS IE for Beacon */
656 if (drv->wps_beacon_ie != NULL) {
657 os_memcpy(&(app_ie->app_buf[ie_len]),
658 wpabuf_head(drv->wps_beacon_ie),
659 wpabuf_len(drv->wps_beacon_ie));
660 app_ie->app_buflen = ie_len + wpabuf_len(drv->wps_beacon_ie);
661 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800662 wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(Beacon)",
663 app_ie->app_buf, app_ie->app_buflen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700664 set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie,
665 sizeof(struct ieee80211req_getset_appiebuf) +
666 app_ie->app_buflen);
667
668 /* append WPS IE for Probe Response */
669 app_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_RESP;
670 if (drv->wps_probe_resp_ie != NULL) {
671 os_memcpy(&(app_ie->app_buf[ie_len]),
672 wpabuf_head(drv->wps_probe_resp_ie),
673 wpabuf_len(drv->wps_probe_resp_ie));
674 app_ie->app_buflen = ie_len +
675 wpabuf_len(drv->wps_probe_resp_ie);
676 } else
677 app_ie->app_buflen = ie_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800678 wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(ProbeResp)",
679 app_ie->app_buf, app_ie->app_buflen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700680 set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie,
681 sizeof(struct ieee80211req_getset_appiebuf) +
682 app_ie->app_buflen);
683 return 0;
684}
685
686static int
687atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
688 int reason_code)
689{
690 struct atheros_driver_data *drv = priv;
691 struct ieee80211req_mlme mlme;
692 int ret;
693
694 wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
695 __func__, ether_sprintf(addr), reason_code);
696
697 mlme.im_op = IEEE80211_MLME_DEAUTH;
698 mlme.im_reason = reason_code;
699 memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
700 ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
701 if (ret < 0) {
702 wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR
703 " reason %d)",
704 __func__, MAC2STR(addr), reason_code);
705 }
706
707 return ret;
708}
709
710static int
711atheros_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
712 int reason_code)
713{
714 struct atheros_driver_data *drv = priv;
715 struct ieee80211req_mlme mlme;
716 int ret;
717
718 wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
719 __func__, ether_sprintf(addr), reason_code);
720
721 mlme.im_op = IEEE80211_MLME_DISASSOC;
722 mlme.im_reason = reason_code;
723 memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
724 ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
725 if (ret < 0) {
726 wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr "
727 MACSTR " reason %d)",
728 __func__, MAC2STR(addr), reason_code);
729 }
730
731 return ret;
732}
733
734#ifdef CONFIG_WPS
Dmitry Shmidt04949592012-07-19 12:16:46 -0700735static void atheros_raw_recv_wps(void *ctx, const u8 *src_addr, const u8 *buf,
736 size_t len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700737{
738 struct atheros_driver_data *drv = ctx;
739 const struct ieee80211_mgmt *mgmt;
740 u16 fc;
741 union wpa_event_data event;
742
743 /* Send Probe Request information to WPS processing */
744
745 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
746 return;
747 mgmt = (const struct ieee80211_mgmt *) buf;
748
749 fc = le_to_host16(mgmt->frame_control);
750 if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
751 WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ)
752 return;
753
754 os_memset(&event, 0, sizeof(event));
755 event.rx_probe_req.sa = mgmt->sa;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800756 event.rx_probe_req.da = mgmt->da;
757 event.rx_probe_req.bssid = mgmt->bssid;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700758 event.rx_probe_req.ie = mgmt->u.probe_req.variable;
759 event.rx_probe_req.ie_len =
760 len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
761 wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event);
762}
763#endif /* CONFIG_WPS */
764
Dmitry Shmidt04949592012-07-19 12:16:46 -0700765#ifdef CONFIG_IEEE80211R
766static void atheros_raw_recv_11r(void *ctx, const u8 *src_addr, const u8 *buf,
767 size_t len)
768{
769 struct atheros_driver_data *drv = ctx;
770 union wpa_event_data event;
771 const struct ieee80211_mgmt *mgmt;
772 u16 fc;
773 u16 stype;
774 int ielen;
775 const u8 *iebuf;
776
777 /* Do 11R processing for ASSOC/AUTH/FT ACTION frames */
778 if (len < IEEE80211_HDRLEN)
779 return;
780 mgmt = (const struct ieee80211_mgmt *) buf;
781
782 fc = le_to_host16(mgmt->frame_control);
783
784 if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
785 return;
786 stype = WLAN_FC_GET_STYPE(fc);
787
788 wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype,
789 (int) len);
790
791 if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
792 wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
793 __func__);
794 return;
795 }
796 switch (stype) {
797 case WLAN_FC_STYPE_ASSOC_REQ:
798 if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.assoc_req))
799 break;
800 ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
801 iebuf = mgmt->u.assoc_req.variable;
802 drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 0);
803 break;
804 case WLAN_FC_STYPE_REASSOC_REQ:
805 if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.reassoc_req))
806 break;
807 ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
808 iebuf = mgmt->u.reassoc_req.variable;
809 drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1);
810 break;
811 case WLAN_FC_STYPE_ACTION:
812 if (&mgmt->u.action.category > buf + len)
813 break;
814 os_memset(&event, 0, sizeof(event));
815 event.rx_action.da = mgmt->da;
816 event.rx_action.sa = mgmt->sa;
817 event.rx_action.bssid = mgmt->bssid;
818 event.rx_action.category = mgmt->u.action.category;
819 event.rx_action.data = &mgmt->u.action.category;
820 event.rx_action.len = buf + len - event.rx_action.data;
821 wpa_supplicant_event(drv->hapd, EVENT_RX_ACTION, &event);
822 break;
823 case WLAN_FC_STYPE_AUTH:
824 if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.auth))
825 break;
826 os_memset(&event, 0, sizeof(event));
827 os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
828 os_memcpy(event.auth.bssid, mgmt->bssid, ETH_ALEN);
829 event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
830 event.auth.status_code =
831 le_to_host16(mgmt->u.auth.status_code);
832 event.auth.auth_transaction =
833 le_to_host16(mgmt->u.auth.auth_transaction);
834 event.auth.ies = mgmt->u.auth.variable;
835 event.auth.ies_len = len - IEEE80211_HDRLEN -
836 sizeof(mgmt->u.auth);
837 wpa_supplicant_event(drv->hapd, EVENT_AUTH, &event);
838 break;
839 default:
840 break;
841 }
842}
843#endif /* CONFIG_IEEE80211R */
844
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700845#ifdef CONFIG_HS20
846static void atheros_raw_recv_hs20(void *ctx, const u8 *src_addr, const u8 *buf,
847 size_t len)
848{
849 struct atheros_driver_data *drv = ctx;
850 const struct ieee80211_mgmt *mgmt;
851 u16 fc;
852 union wpa_event_data event;
853
854 /* Send the Action frame for HS20 processing */
855
856 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.action.category) +
857 sizeof(mgmt->u.action.u.public_action))
858 return;
859
860 mgmt = (const struct ieee80211_mgmt *) buf;
861
862 fc = le_to_host16(mgmt->frame_control);
863 if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
864 WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION ||
865 mgmt->u.action.category != WLAN_ACTION_PUBLIC)
866 return;
867
868 wpa_printf(MSG_DEBUG, "%s:Received Public Action frame", __func__);
869
870 os_memset(&event, 0, sizeof(event));
871 event.rx_mgmt.frame = (const u8 *) mgmt;
872 event.rx_mgmt.frame_len = len;
873 wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
874}
Dmitry Shmidt051af732013-10-22 13:52:46 -0700875
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700876#endif /* CONFIG_HS20 */
877
Dmitry Shmidt051af732013-10-22 13:52:46 -0700878
879static int atheros_set_qos_map(void *ctx, const u8 *qos_map_set,
880 u8 qos_map_set_len)
881{
882#ifdef CONFIG_ATHEROS_QOS_MAP
883 struct atheros_driver_data *drv = ctx;
884 struct ieee80211req_athdbg req;
885 struct ieee80211_qos_map *qos_map = &req.data.qos_map;
886 struct iwreq iwr;
887 int i, up_start;
888
889 if (qos_map_set_len < 16 || qos_map_set_len > 58 ||
890 qos_map_set_len & 1) {
891 wpa_printf(MSG_ERROR, "Invalid QoS Map");
892 return -1;
893 } else {
894 memset(&req, 0, sizeof(struct ieee80211req_athdbg));
895 req.cmd = IEEE80211_DBGREQ_SETQOSMAPCONF;
896 os_memset(&iwr, 0, sizeof(iwr));
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700897 os_strlcpy(iwr.ifr_name, drv->iface, sizeof(iwr.ifr_name));
Dmitry Shmidt051af732013-10-22 13:52:46 -0700898 iwr.u.data.pointer = (void *) &req;
899 iwr.u.data.length = sizeof(struct ieee80211req_athdbg);
900 }
901
902 qos_map->valid = 1;
903 qos_map->num_dscp_except = (qos_map_set_len - 16) / 2;
904 if (qos_map->num_dscp_except) {
905 for (i = 0; i < qos_map->num_dscp_except; i++) {
906 qos_map->dscp_exception[i].dscp = qos_map_set[i * 2];
907 qos_map->dscp_exception[i].up = qos_map_set[i * 2 + 1];
908 }
909 }
910
911 up_start = qos_map_set_len - 16;
912 for (i = 0; i < IEEE80211_MAX_QOS_UP_RANGE; i++) {
913 qos_map->up[i].low = qos_map_set[up_start + (i * 2)];
914 qos_map->up[i].high = qos_map_set[up_start + (i * 2) + 1];
915 }
916
917 if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_DBGREQ, &iwr) < 0) {
918 perror("ioctl[IEEE80211_IOCTL_DBGREQ]");
919 wpa_printf(MSG_DEBUG, "%s: %s: Failed to set QoS Map",
920 __func__, drv->iface);
921 return -1;
922 }
923#endif /* CONFIG_ATHEROS_QOS_MAP */
924
925 return 0;
926}
927
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800928#if defined(CONFIG_WNM) && !defined(CONFIG_IEEE80211R)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700929static void atheros_raw_recv_11v(void *ctx, const u8 *src_addr, const u8 *buf,
930 size_t len)
931{
932 struct atheros_driver_data *drv = ctx;
933 union wpa_event_data event;
934 const struct ieee80211_mgmt *mgmt;
935 u16 fc;
936 u16 stype;
937
938 /* Do 11R processing for WNM ACTION frames */
939 if (len < IEEE80211_HDRLEN)
940 return;
941 mgmt = (const struct ieee80211_mgmt *) buf;
942
943 fc = le_to_host16(mgmt->frame_control);
944
945 if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
946 return;
947 stype = WLAN_FC_GET_STYPE(fc);
948
949 wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype,
950 (int) len);
951
952 if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
953 wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
954 __func__);
955 return;
956 }
957
958 switch (stype) {
959 case WLAN_FC_STYPE_ACTION:
960 if (&mgmt->u.action.category > buf + len)
961 break;
962 os_memset(&event, 0, sizeof(event));
963 event.rx_action.da = mgmt->da;
964 event.rx_action.sa = mgmt->sa;
965 event.rx_action.bssid = mgmt->bssid;
966 event.rx_action.category = mgmt->u.action.category;
967 event.rx_action.data = &mgmt->u.action.category;
968 event.rx_action.len = buf + len - event.rx_action.data;
969 wpa_supplicant_event(drv->hapd, EVENT_RX_ACTION, &event);
970 break;
971 default:
972 break;
973 }
974}
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800975#endif /* CONFIG_WNM */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700976
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800977#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_WNM)
Dmitry Shmidt04949592012-07-19 12:16:46 -0700978static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
979 size_t len)
980{
981#ifdef CONFIG_WPS
982 atheros_raw_recv_wps(ctx, src_addr, buf, len);
983#endif /* CONFIG_WPS */
984#ifdef CONFIG_IEEE80211R
985 atheros_raw_recv_11r(ctx, src_addr, buf, len);
986#endif /* CONFIG_IEEE80211R */
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800987#if defined(CONFIG_WNM) && !defined(CONFIG_IEEE80211R)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700988 atheros_raw_recv_11v(ctx, src_addr, buf, len);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800989#endif /* CONFIG_WNM */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700990#ifdef CONFIG_HS20
991 atheros_raw_recv_hs20(ctx, src_addr, buf, len);
992#endif /* CONFIG_HS20 */
Dmitry Shmidt04949592012-07-19 12:16:46 -0700993}
994#endif /* CONFIG_WPS || CONFIG_IEEE80211R */
995
996static int atheros_receive_pkt(struct atheros_driver_data *drv)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700997{
998 int ret = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700999 struct ieee80211req_set_filter filt;
1000
1001 wpa_printf(MSG_DEBUG, "%s Enter", __func__);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001002 filt.app_filterype = 0;
1003#ifdef CONFIG_WPS
1004 filt.app_filterype |= IEEE80211_FILTER_TYPE_PROBE_REQ;
1005#endif /* CONFIG_WPS */
1006#ifdef CONFIG_IEEE80211R
1007 filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ |
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001008 IEEE80211_FILTER_TYPE_AUTH |
1009 IEEE80211_FILTER_TYPE_ACTION);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001010#endif
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001011#ifdef CONFIG_WNM
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001012 filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001013#endif /* CONFIG_WNM */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001014#ifdef CONFIG_HS20
1015 filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
1016#endif /* CONFIG_HS20 */
Dmitry Shmidt04949592012-07-19 12:16:46 -07001017 if (filt.app_filterype) {
1018 ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
1019 sizeof(struct ieee80211req_set_filter));
1020 if (ret)
1021 return ret;
1022 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001023
Dmitry Shmidt04949592012-07-19 12:16:46 -07001024#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001025 drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW,
1026 atheros_raw_receive, drv, 1);
1027 if (drv->sock_raw == NULL)
1028 return -1;
Dmitry Shmidt04949592012-07-19 12:16:46 -07001029#endif /* CONFIG_WPS || CONFIG_IEEE80211R */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001030 return ret;
1031}
1032
Dmitry Shmidt04949592012-07-19 12:16:46 -07001033static int atheros_reset_appfilter(struct atheros_driver_data *drv)
1034{
1035 struct ieee80211req_set_filter filt;
1036 filt.app_filterype = 0;
1037 return set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
1038 sizeof(struct ieee80211req_set_filter));
1039}
1040
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001041#ifdef CONFIG_WPS
1042static int
1043atheros_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype)
1044{
1045 struct atheros_driver_data *drv = priv;
1046 u8 buf[512];
1047 struct ieee80211req_getset_appiebuf *beac_ie;
1048
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001049 wpa_printf(MSG_DEBUG, "%s buflen = %lu frametype=%u", __func__,
1050 (unsigned long) len, frametype);
1051 wpa_hexdump(MSG_DEBUG, "atheros: IE", ie, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001052
1053 beac_ie = (struct ieee80211req_getset_appiebuf *) buf;
1054 beac_ie->app_frmtype = frametype;
1055 beac_ie->app_buflen = len;
1056 os_memcpy(&(beac_ie->app_buf[0]), ie, len);
1057
1058 /* append the WPA/RSN IE if it is set already */
1059 if (((frametype == IEEE80211_APPIE_FRAME_BEACON) ||
1060 (frametype == IEEE80211_APPIE_FRAME_PROBE_RESP)) &&
1061 (drv->wpa_ie != NULL)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001062 wpa_hexdump_buf(MSG_DEBUG, "atheros: Append WPA/RSN IE",
1063 drv->wpa_ie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001064 os_memcpy(&(beac_ie->app_buf[len]), wpabuf_head(drv->wpa_ie),
1065 wpabuf_len(drv->wpa_ie));
1066 beac_ie->app_buflen += wpabuf_len(drv->wpa_ie);
1067 }
1068
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001069 wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF",
1070 beac_ie->app_buf, beac_ie->app_buflen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001071 return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie,
1072 sizeof(struct ieee80211req_getset_appiebuf) +
1073 beac_ie->app_buflen);
1074}
1075
1076static int
1077atheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
1078 const struct wpabuf *proberesp,
1079 const struct wpabuf *assocresp)
1080{
1081 struct atheros_driver_data *drv = priv;
1082
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001083 wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - beacon", beacon);
1084 wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - proberesp",
1085 proberesp);
1086 wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - assocresp",
1087 assocresp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001088 wpabuf_free(drv->wps_beacon_ie);
1089 drv->wps_beacon_ie = beacon ? wpabuf_dup(beacon) : NULL;
1090 wpabuf_free(drv->wps_probe_resp_ie);
1091 drv->wps_probe_resp_ie = proberesp ? wpabuf_dup(proberesp) : NULL;
1092
1093 atheros_set_wps_ie(priv, assocresp ? wpabuf_head(assocresp) : NULL,
1094 assocresp ? wpabuf_len(assocresp) : 0,
1095 IEEE80211_APPIE_FRAME_ASSOC_RESP);
1096 if (atheros_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL,
1097 beacon ? wpabuf_len(beacon) : 0,
1098 IEEE80211_APPIE_FRAME_BEACON))
1099 return -1;
1100 return atheros_set_wps_ie(priv,
1101 proberesp ? wpabuf_head(proberesp) : NULL,
1102 proberesp ? wpabuf_len(proberesp): 0,
1103 IEEE80211_APPIE_FRAME_PROBE_RESP);
1104}
1105#else /* CONFIG_WPS */
1106#define atheros_set_ap_wps_ie NULL
1107#endif /* CONFIG_WPS */
1108
Dmitry Shmidt04949592012-07-19 12:16:46 -07001109#ifdef CONFIG_IEEE80211R
1110static int
1111atheros_sta_auth(void *priv, const u8 *own_addr, const u8 *addr, u16 seq,
1112 u16 status_code, const u8 *ie, size_t len)
1113{
1114 struct atheros_driver_data *drv = priv;
1115 struct ieee80211req_mlme mlme;
1116 int ret;
1117
1118 wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d",
1119 __func__, ether_sprintf(addr), status_code);
1120
1121 mlme.im_op = IEEE80211_MLME_AUTH;
1122 mlme.im_reason = status_code;
1123 mlme.im_seq = seq;
1124 os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
1125 mlme.im_optie_len = len;
1126 if (len) {
1127 if (len < IEEE80211_MAX_OPT_IE) {
1128 os_memcpy(mlme.im_optie, ie, len);
1129 } else {
1130 wpa_printf(MSG_DEBUG, "%s: Not enough space to copy "
1131 "opt_ie STA (addr " MACSTR " reason %d, "
1132 "ie_len %d)",
1133 __func__, MAC2STR(addr), status_code,
1134 (int) len);
1135 return -1;
1136 }
1137 }
1138 ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
1139 if (ret < 0) {
1140 wpa_printf(MSG_DEBUG, "%s: Failed to auth STA (addr " MACSTR
1141 " reason %d)",
1142 __func__, MAC2STR(addr), status_code);
1143 }
1144 return ret;
1145}
1146
1147static int
1148atheros_sta_assoc(void *priv, const u8 *own_addr, const u8 *addr,
1149 int reassoc, u16 status_code, const u8 *ie, size_t len)
1150{
1151 struct atheros_driver_data *drv = priv;
1152 struct ieee80211req_mlme mlme;
1153 int ret;
1154
1155 wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d reassoc %d",
1156 __func__, ether_sprintf(addr), status_code, reassoc);
1157
1158 if (reassoc)
1159 mlme.im_op = IEEE80211_MLME_REASSOC;
1160 else
1161 mlme.im_op = IEEE80211_MLME_ASSOC;
1162 mlme.im_reason = status_code;
1163 os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
1164 mlme.im_optie_len = len;
1165 if (len) {
1166 if (len < IEEE80211_MAX_OPT_IE) {
1167 os_memcpy(mlme.im_optie, ie, len);
1168 } else {
1169 wpa_printf(MSG_DEBUG, "%s: Not enough space to copy "
1170 "opt_ie STA (addr " MACSTR " reason %d, "
1171 "ie_len %d)",
1172 __func__, MAC2STR(addr), status_code,
1173 (int) len);
1174 return -1;
1175 }
1176 }
1177 ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
1178 if (ret < 0) {
1179 wpa_printf(MSG_DEBUG, "%s: Failed to assoc STA (addr " MACSTR
1180 " reason %d)",
1181 __func__, MAC2STR(addr), status_code);
1182 }
1183 return ret;
1184}
1185#endif /* CONFIG_IEEE80211R */
1186
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001187static void
1188atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
1189{
1190 struct hostapd_data *hapd = drv->hapd;
1191 struct ieee80211req_wpaie ie;
1192 int ielen = 0;
1193 u8 *iebuf = NULL;
1194
1195 /*
1196 * Fetch negotiated WPA/RSN parameters from the system.
1197 */
1198 memset(&ie, 0, sizeof(ie));
1199 memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
1200 if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) {
1201 /*
1202 * See ATH_WPS_IE comment in the beginning of the file for a
1203 * possible cause for the failure..
1204 */
1205 wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE: %s",
1206 __func__, strerror(errno));
1207 goto no_ie;
1208 }
1209 wpa_hexdump(MSG_MSGDUMP, "atheros req WPA IE",
1210 ie.wpa_ie, IEEE80211_MAX_OPT_IE);
1211 wpa_hexdump(MSG_MSGDUMP, "atheros req RSN IE",
1212 ie.rsn_ie, IEEE80211_MAX_OPT_IE);
1213#ifdef ATH_WPS_IE
1214 wpa_hexdump(MSG_MSGDUMP, "atheros req WPS IE",
1215 ie.wps_ie, IEEE80211_MAX_OPT_IE);
1216#endif /* ATH_WPS_IE */
1217 iebuf = ie.wpa_ie;
1218 /* atheros seems to return some random data if WPA/RSN IE is not set.
1219 * Assume the IE was not included if the IE type is unknown. */
1220 if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC)
1221 iebuf[1] = 0;
1222 if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) {
1223 /* atheros-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not
1224 * set. This is needed for WPA2. */
1225 iebuf = ie.rsn_ie;
1226 if (iebuf[0] != WLAN_EID_RSN)
1227 iebuf[1] = 0;
1228 }
1229
1230 ielen = iebuf[1];
1231
1232#ifdef ATH_WPS_IE
1233 /* if WPS IE is present, preference is given to WPS */
1234 if (ie.wps_ie &&
1235 (ie.wps_ie[1] > 0 && (ie.wps_ie[0] == WLAN_EID_VENDOR_SPECIFIC))) {
1236 iebuf = ie.wps_ie;
1237 ielen = ie.wps_ie[1];
1238 }
1239#endif /* ATH_WPS_IE */
1240
1241 if (ielen == 0)
1242 iebuf = NULL;
1243 else
1244 ielen += 2;
1245
1246no_ie:
1247 drv_event_assoc(hapd, addr, iebuf, ielen, 0);
1248
1249 if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
1250 /* Cached accounting data is not valid anymore. */
1251 memset(drv->acct_mac, 0, ETH_ALEN);
1252 memset(&drv->acct_data, 0, sizeof(drv->acct_data));
1253 }
1254}
1255
1256static void
1257atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
1258 char *custom, char *end)
1259{
1260 wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
1261
1262 if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
1263 char *pos;
1264 u8 addr[ETH_ALEN];
1265 pos = strstr(custom, "addr=");
1266 if (pos == NULL) {
1267 wpa_printf(MSG_DEBUG,
1268 "MLME-MICHAELMICFAILURE.indication "
1269 "without sender address ignored");
1270 return;
1271 }
1272 pos += 5;
1273 if (hwaddr_aton(pos, addr) == 0) {
1274 union wpa_event_data data;
1275 os_memset(&data, 0, sizeof(data));
1276 data.michael_mic_failure.unicast = 1;
1277 data.michael_mic_failure.src = addr;
1278 wpa_supplicant_event(drv->hapd,
1279 EVENT_MICHAEL_MIC_FAILURE, &data);
1280 } else {
1281 wpa_printf(MSG_DEBUG,
1282 "MLME-MICHAELMICFAILURE.indication "
1283 "with invalid MAC address");
1284 }
1285 } else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) {
1286 char *key, *value;
1287 u32 val;
1288 key = custom;
1289 while ((key = strchr(key, '\n')) != NULL) {
1290 key++;
1291 value = strchr(key, '=');
1292 if (value == NULL)
1293 continue;
1294 *value++ = '\0';
1295 val = strtoul(value, NULL, 10);
1296 if (strcmp(key, "mac") == 0)
1297 hwaddr_aton(value, drv->acct_mac);
1298 else if (strcmp(key, "rx_packets") == 0)
1299 drv->acct_data.rx_packets = val;
1300 else if (strcmp(key, "tx_packets") == 0)
1301 drv->acct_data.tx_packets = val;
1302 else if (strcmp(key, "rx_bytes") == 0)
1303 drv->acct_data.rx_bytes = val;
1304 else if (strcmp(key, "tx_bytes") == 0)
1305 drv->acct_data.tx_bytes = val;
1306 key = value;
1307 }
1308#ifdef CONFIG_WPS
1309 } else if (strncmp(custom, "PUSH-BUTTON.indication", 22) == 0) {
1310 /* Some atheros kernels send push button as a wireless event */
1311 /* PROBLEM! this event is received for ALL BSSs ...
1312 * so all are enabled for WPS... ugh.
1313 */
1314 wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001315#endif /* CONFIG_WPS */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001316#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20)
1317#define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001318 } else if (strncmp(custom, "Manage.prob_req ", 16) == 0) {
1319 /*
1320 * Atheros driver uses a hack to pass Probe Request frames as a
1321 * binary data in the custom wireless event. The old way (using
1322 * packet sniffing) didn't work when bridging.
1323 * Format: "Manage.prob_req <frame len>" | zero padding | frame
1324 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001325 int len = atoi(custom + 16);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001326 if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001327 wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req event "
1328 "length %d", len);
1329 return;
1330 }
1331 atheros_raw_receive(drv, NULL,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001332 (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001333 } else if (strncmp(custom, "Manage.assoc_req ", 17) == 0) {
1334 /* Format: "Manage.assoc_req <frame len>" | zero padding |
1335 * frame */
1336 int len = atoi(custom + 17);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001337 if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001338 wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
1339 "assoc_req/auth event length %d", len);
1340 return;
1341 }
1342 atheros_raw_receive(drv, NULL,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001343 (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001344 } else if (strncmp(custom, "Manage.action ", 14) == 0) {
1345 /* Format: "Manage.assoc_req <frame len>" | zero padding |
1346 * frame */
1347 int len = atoi(custom + 14);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001348 if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001349 wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
1350 "assoc_req/auth event length %d", len);
1351 return;
1352 }
1353 atheros_raw_receive(drv, NULL,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001354 (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001355 } else if (strncmp(custom, "Manage.auth ", 12) == 0) {
1356 /* Format: "Manage.auth <frame len>" | zero padding | frame
1357 */
1358 int len = atoi(custom + 12);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001359 if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001360 wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
1361 "assoc_req/auth event length %d", len);
1362 return;
1363 }
1364 atheros_raw_receive(drv, NULL,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001365 (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001366#endif /* CONFIG_WPS or CONFIG_IEEE80211R */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001367 }
1368}
1369
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001370/*
1371* Handle size of data problem. WEXT only allows data of 256 bytes for custom
1372* events, and p2p data can be much bigger. So the athr driver sends a small
1373* event telling me to collect the big data with an ioctl.
1374* On the first event, send all pending events to supplicant.
1375*/
1376static void fetch_pending_big_events(struct atheros_driver_data *drv)
1377{
1378 union wpa_event_data event;
1379 const struct ieee80211_mgmt *mgmt;
1380 u8 tbuf[IW_PRIV_SIZE_MASK]; /* max size is 2047 bytes */
1381 u16 fc, stype;
1382 struct iwreq iwr;
1383 size_t data_len;
1384 u32 freq, frame_type;
1385
1386 while (1) {
1387 os_memset(&iwr, 0, sizeof(iwr));
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001388 os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001389
1390 iwr.u.data.pointer = (void *) tbuf;
1391 iwr.u.data.length = sizeof(tbuf);
1392 iwr.u.data.flags = IEEE80211_IOC_P2P_FETCH_FRAME;
1393
1394 if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr)
1395 < 0) {
1396 if (errno == ENOSPC) {
1397 wpa_printf(MSG_DEBUG, "%s:%d exit",
1398 __func__, __LINE__);
1399 return;
1400 }
1401 wpa_printf(MSG_DEBUG, "athr: %s: P2P_BIG_PARAM["
1402 "P2P_FETCH_FRAME] failed: %s",
1403 __func__, strerror(errno));
1404 return;
1405 }
1406 data_len = iwr.u.data.length;
1407 wpa_hexdump(MSG_DEBUG, "athr: P2P_FETCH_FRAME data",
1408 (u8 *) tbuf, data_len);
1409 if (data_len < sizeof(freq) + sizeof(frame_type) + 24) {
1410 wpa_printf(MSG_DEBUG, "athr: frame too short");
1411 continue;
1412 }
1413 os_memcpy(&freq, tbuf, sizeof(freq));
1414 os_memcpy(&frame_type, &tbuf[sizeof(freq)],
1415 sizeof(frame_type));
1416 mgmt = (void *) &tbuf[sizeof(freq) + sizeof(frame_type)];
1417 data_len -= sizeof(freq) + sizeof(frame_type);
1418
1419 if (frame_type == IEEE80211_EV_RX_MGMT) {
1420 fc = le_to_host16(mgmt->frame_control);
1421 stype = WLAN_FC_GET_STYPE(fc);
1422
1423 wpa_printf(MSG_DEBUG, "athr: EV_RX_MGMT stype=%u "
1424 "freq=%u len=%u", stype, freq, (int) data_len);
1425
1426 if (stype == WLAN_FC_STYPE_ACTION) {
1427 os_memset(&event, 0, sizeof(event));
1428 event.rx_mgmt.frame = (const u8 *) mgmt;
1429 event.rx_mgmt.frame_len = data_len;
1430 wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT,
1431 &event);
1432 continue;
1433 }
1434 } else {
1435 wpa_printf(MSG_DEBUG, "athr: %s unknown type %d",
1436 __func__, frame_type);
1437 continue;
1438 }
1439 }
1440}
1441
1442static void
1443atheros_wireless_event_atheros_custom(struct atheros_driver_data *drv,
1444 int opcode, char *buf, int len)
1445{
1446 switch (opcode) {
1447 case IEEE80211_EV_RX_MGMT:
1448 wpa_printf(MSG_DEBUG, "WEXT: EV_RX_MGMT");
1449 fetch_pending_big_events(drv);
1450 break;
1451 default:
1452 break;
1453 }
1454}
1455
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001456static void
1457atheros_wireless_event_wireless(struct atheros_driver_data *drv,
1458 char *data, int len)
1459{
1460 struct iw_event iwe_buf, *iwe = &iwe_buf;
1461 char *pos, *end, *custom, *buf;
1462
1463 pos = data;
1464 end = data + len;
1465
1466 while (pos + IW_EV_LCP_LEN <= end) {
1467 /* Event data may be unaligned, so make a local, aligned copy
1468 * before processing. */
1469 memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
1470 wpa_printf(MSG_MSGDUMP, "Wireless event: cmd=0x%x len=%d",
1471 iwe->cmd, iwe->len);
1472 if (iwe->len <= IW_EV_LCP_LEN)
1473 return;
1474
1475 custom = pos + IW_EV_POINT_LEN;
1476 if (drv->we_version > 18 &&
1477 (iwe->cmd == IWEVMICHAELMICFAILURE ||
1478 iwe->cmd == IWEVASSOCREQIE ||
1479 iwe->cmd == IWEVCUSTOM)) {
1480 /* WE-19 removed the pointer from struct iw_point */
1481 char *dpos = (char *) &iwe_buf.u.data.length;
1482 int dlen = dpos - (char *) &iwe_buf;
1483 memcpy(dpos, pos + IW_EV_LCP_LEN,
1484 sizeof(struct iw_event) - dlen);
1485 } else {
1486 memcpy(&iwe_buf, pos, sizeof(struct iw_event));
1487 custom += IW_EV_POINT_OFF;
1488 }
1489
1490 switch (iwe->cmd) {
1491 case IWEVEXPIRED:
1492 drv_event_disassoc(drv->hapd,
1493 (u8 *) iwe->u.addr.sa_data);
1494 break;
1495 case IWEVREGISTERED:
1496 atheros_new_sta(drv, (u8 *) iwe->u.addr.sa_data);
1497 break;
1498 case IWEVASSOCREQIE:
1499 /* Driver hack.. Use IWEVASSOCREQIE to bypass
1500 * IWEVCUSTOM size limitations. Need to handle this
1501 * just like IWEVCUSTOM.
1502 */
1503 case IWEVCUSTOM:
1504 if (custom + iwe->u.data.length > end)
1505 return;
1506 buf = malloc(iwe->u.data.length + 1);
1507 if (buf == NULL)
1508 return; /* XXX */
1509 memcpy(buf, custom, iwe->u.data.length);
1510 buf[iwe->u.data.length] = '\0';
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001511
1512 if (iwe->u.data.flags != 0) {
1513 atheros_wireless_event_atheros_custom(
1514 drv, (int) iwe->u.data.flags,
1515 buf, len);
1516 } else {
1517 atheros_wireless_event_wireless_custom(
1518 drv, buf, buf + iwe->u.data.length);
1519 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001520 free(buf);
1521 break;
1522 }
1523
1524 pos += iwe->len;
1525 }
1526}
1527
1528
1529static void
1530atheros_wireless_event_rtm_newlink(void *ctx,
1531 struct ifinfomsg *ifi, u8 *buf, size_t len)
1532{
1533 struct atheros_driver_data *drv = ctx;
1534 int attrlen, rta_len;
1535 struct rtattr *attr;
1536
1537 if (ifi->ifi_index != drv->ifindex)
1538 return;
1539
1540 attrlen = len;
1541 attr = (struct rtattr *) buf;
1542
1543 rta_len = RTA_ALIGN(sizeof(struct rtattr));
1544 while (RTA_OK(attr, attrlen)) {
1545 if (attr->rta_type == IFLA_WIRELESS) {
1546 atheros_wireless_event_wireless(
1547 drv, ((char *) attr) + rta_len,
1548 attr->rta_len - rta_len);
1549 }
1550 attr = RTA_NEXT(attr, attrlen);
1551 }
1552}
1553
1554
1555static int
1556atheros_get_we_version(struct atheros_driver_data *drv)
1557{
1558 struct iw_range *range;
1559 struct iwreq iwr;
1560 int minlen;
1561 size_t buflen;
1562
1563 drv->we_version = 0;
1564
1565 /*
1566 * Use larger buffer than struct iw_range in order to allow the
1567 * structure to grow in the future.
1568 */
1569 buflen = sizeof(struct iw_range) + 500;
1570 range = os_zalloc(buflen);
1571 if (range == NULL)
1572 return -1;
1573
1574 memset(&iwr, 0, sizeof(iwr));
1575 os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
1576 iwr.u.data.pointer = (caddr_t) range;
1577 iwr.u.data.length = buflen;
1578
1579 minlen = ((char *) &range->enc_capa) - (char *) range +
1580 sizeof(range->enc_capa);
1581
1582 if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
1583 perror("ioctl[SIOCGIWRANGE]");
1584 free(range);
1585 return -1;
1586 } else if (iwr.u.data.length >= minlen &&
1587 range->we_version_compiled >= 18) {
1588 wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
1589 "WE(source)=%d enc_capa=0x%x",
1590 range->we_version_compiled,
1591 range->we_version_source,
1592 range->enc_capa);
1593 drv->we_version = range->we_version_compiled;
1594 }
1595
Jouni Malinen75ecf522011-06-27 15:19:46 -07001596 os_free(range);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001597 return 0;
1598}
1599
1600
1601static int
1602atheros_wireless_event_init(struct atheros_driver_data *drv)
1603{
1604 struct netlink_config *cfg;
1605
1606 atheros_get_we_version(drv);
1607
1608 cfg = os_zalloc(sizeof(*cfg));
1609 if (cfg == NULL)
1610 return -1;
1611 cfg->ctx = drv;
1612 cfg->newlink_cb = atheros_wireless_event_rtm_newlink;
1613 drv->netlink = netlink_init(cfg);
1614 if (drv->netlink == NULL) {
1615 os_free(cfg);
1616 return -1;
1617 }
1618
1619 return 0;
1620}
1621
1622
1623static int
1624atheros_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
1625 int encrypt, const u8 *own_addr, u32 flags)
1626{
1627 struct atheros_driver_data *drv = priv;
1628 unsigned char buf[3000];
1629 unsigned char *bp = buf;
1630 struct l2_ethhdr *eth;
1631 size_t len;
1632 int status;
1633
1634 /*
1635 * Prepend the Ethernet header. If the caller left us
1636 * space at the front we could just insert it but since
1637 * we don't know we copy to a local buffer. Given the frequency
1638 * and size of frames this probably doesn't matter.
1639 */
1640 len = data_len + sizeof(struct l2_ethhdr);
1641 if (len > sizeof(buf)) {
1642 bp = malloc(len);
1643 if (bp == NULL) {
1644 printf("EAPOL frame discarded, cannot malloc temp "
1645 "buffer of size %lu!\n", (unsigned long) len);
1646 return -1;
1647 }
1648 }
1649 eth = (struct l2_ethhdr *) bp;
1650 memcpy(eth->h_dest, addr, ETH_ALEN);
1651 memcpy(eth->h_source, own_addr, ETH_ALEN);
1652 eth->h_proto = host_to_be16(ETH_P_EAPOL);
1653 memcpy(eth+1, data, data_len);
1654
1655 wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len);
1656
1657 status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len);
1658
1659 if (bp != buf)
1660 free(bp);
1661 return status;
1662}
1663
1664static void
1665handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
1666{
1667 struct atheros_driver_data *drv = ctx;
1668 drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr),
1669 len - sizeof(struct l2_ethhdr));
1670}
1671
1672static void *
1673atheros_init(struct hostapd_data *hapd, struct wpa_init_params *params)
1674{
1675 struct atheros_driver_data *drv;
1676 struct ifreq ifr;
1677 struct iwreq iwr;
1678 char brname[IFNAMSIZ];
1679
1680 drv = os_zalloc(sizeof(struct atheros_driver_data));
1681 if (drv == NULL) {
1682 printf("Could not allocate memory for atheros driver data\n");
1683 return NULL;
1684 }
1685
1686 drv->hapd = hapd;
1687 drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
1688 if (drv->ioctl_sock < 0) {
1689 perror("socket[PF_INET,SOCK_DGRAM]");
1690 goto bad;
1691 }
1692 memcpy(drv->iface, params->ifname, sizeof(drv->iface));
1693
1694 memset(&ifr, 0, sizeof(ifr));
1695 os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
1696 if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) {
1697 perror("ioctl(SIOCGIFINDEX)");
1698 goto bad;
1699 }
1700 drv->ifindex = ifr.ifr_ifindex;
1701
1702 drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL,
1703 handle_read, drv, 1);
1704 if (drv->sock_xmit == NULL)
1705 goto bad;
1706 if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
1707 goto bad;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001708 os_memcpy(drv->own_addr, params->own_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001709 if (params->bridge[0]) {
1710 wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.",
1711 params->bridge[0]);
1712 drv->sock_recv = l2_packet_init(params->bridge[0], NULL,
1713 ETH_P_EAPOL, handle_read, drv,
1714 1);
1715 if (drv->sock_recv == NULL)
1716 goto bad;
1717 } else if (linux_br_get(brname, drv->iface) == 0) {
1718 wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for "
1719 "EAPOL receive", brname);
1720 drv->sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL,
1721 handle_read, drv, 1);
1722 if (drv->sock_recv == NULL)
1723 goto bad;
1724 } else
1725 drv->sock_recv = drv->sock_xmit;
1726
1727 memset(&iwr, 0, sizeof(iwr));
1728 os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
1729
1730 iwr.u.mode = IW_MODE_MASTER;
1731
1732 if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
1733 perror("ioctl[SIOCSIWMODE]");
1734 printf("Could not set interface to master mode!\n");
1735 goto bad;
1736 }
1737
1738 /* mark down during setup */
1739 linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
1740 atheros_set_privacy(drv, 0); /* default to no privacy */
1741
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001742 if (atheros_receive_pkt(drv))
1743 goto bad;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001744
1745 if (atheros_wireless_event_init(drv))
1746 goto bad;
1747
1748 return drv;
1749bad:
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001750 atheros_reset_appfilter(drv);
1751 if (drv->sock_raw)
1752 l2_packet_deinit(drv->sock_raw);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001753 if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
1754 l2_packet_deinit(drv->sock_recv);
1755 if (drv->sock_xmit != NULL)
1756 l2_packet_deinit(drv->sock_xmit);
1757 if (drv->ioctl_sock >= 0)
1758 close(drv->ioctl_sock);
1759 if (drv != NULL)
1760 free(drv);
1761 return NULL;
1762}
1763
1764
1765static void
1766atheros_deinit(void *priv)
1767{
1768 struct atheros_driver_data *drv = priv;
1769
Dmitry Shmidt04949592012-07-19 12:16:46 -07001770 atheros_reset_appfilter(drv);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001771 netlink_deinit(drv->netlink);
1772 (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
1773 if (drv->ioctl_sock >= 0)
1774 close(drv->ioctl_sock);
1775 if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
1776 l2_packet_deinit(drv->sock_recv);
1777 if (drv->sock_xmit != NULL)
1778 l2_packet_deinit(drv->sock_xmit);
1779 if (drv->sock_raw)
1780 l2_packet_deinit(drv->sock_raw);
1781 wpabuf_free(drv->wpa_ie);
1782 wpabuf_free(drv->wps_beacon_ie);
1783 wpabuf_free(drv->wps_probe_resp_ie);
1784 free(drv);
1785}
1786
1787static int
1788atheros_set_ssid(void *priv, const u8 *buf, int len)
1789{
1790 struct atheros_driver_data *drv = priv;
1791 struct iwreq iwr;
1792
1793 memset(&iwr, 0, sizeof(iwr));
1794 os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
1795 iwr.u.essid.flags = 1; /* SSID active */
1796 iwr.u.essid.pointer = (caddr_t) buf;
1797 iwr.u.essid.length = len + 1;
1798
1799 if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
1800 perror("ioctl[SIOCSIWESSID]");
1801 printf("len=%d\n", len);
1802 return -1;
1803 }
1804 return 0;
1805}
1806
1807static int
1808atheros_get_ssid(void *priv, u8 *buf, int len)
1809{
1810 struct atheros_driver_data *drv = priv;
1811 struct iwreq iwr;
1812 int ret = 0;
1813
1814 memset(&iwr, 0, sizeof(iwr));
1815 os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
1816 iwr.u.essid.pointer = (caddr_t) buf;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001817 iwr.u.essid.length = (len > IW_ESSID_MAX_SIZE) ?
1818 IW_ESSID_MAX_SIZE : len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001819
1820 if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
1821 perror("ioctl[SIOCGIWESSID]");
1822 ret = -1;
1823 } else
1824 ret = iwr.u.essid.length;
1825
1826 return ret;
1827}
1828
1829static int
1830atheros_set_countermeasures(void *priv, int enabled)
1831{
1832 struct atheros_driver_data *drv = priv;
1833 wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
1834 return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled);
1835}
1836
1837static int
1838atheros_commit(void *priv)
1839{
1840 struct atheros_driver_data *drv = priv;
1841 return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);
1842}
1843
Jouni Malinen75ecf522011-06-27 15:19:46 -07001844static int atheros_set_authmode(void *priv, int auth_algs)
1845{
1846 int authmode;
1847
1848 if ((auth_algs & WPA_AUTH_ALG_OPEN) &&
1849 (auth_algs & WPA_AUTH_ALG_SHARED))
1850 authmode = IEEE80211_AUTH_AUTO;
1851 else if (auth_algs & WPA_AUTH_ALG_OPEN)
1852 authmode = IEEE80211_AUTH_OPEN;
1853 else if (auth_algs & WPA_AUTH_ALG_SHARED)
1854 authmode = IEEE80211_AUTH_SHARED;
1855 else
1856 return -1;
1857
1858 return set80211param(priv, IEEE80211_PARAM_AUTHMODE, authmode);
1859}
1860
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001861static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params)
1862{
1863 /*
1864 * TODO: Use this to replace set_authmode, set_privacy, set_ieee8021x,
1865 * set_generic_elem, and hapd_set_ssid.
1866 */
1867
1868 wpa_printf(MSG_DEBUG, "atheros: set_ap - pairwise_ciphers=0x%x "
1869 "group_cipher=0x%x key_mgmt_suites=0x%x auth_algs=0x%x "
1870 "wpa_version=0x%x privacy=%d interworking=%d",
1871 params->pairwise_ciphers, params->group_cipher,
1872 params->key_mgmt_suites, params->auth_algs,
1873 params->wpa_version, params->privacy, params->interworking);
1874 wpa_hexdump_ascii(MSG_DEBUG, "atheros: SSID",
1875 params->ssid, params->ssid_len);
1876 if (params->hessid)
1877 wpa_printf(MSG_DEBUG, "atheros: HESSID " MACSTR,
1878 MAC2STR(params->hessid));
1879 wpa_hexdump_buf(MSG_DEBUG, "atheros: beacon_ies",
1880 params->beacon_ies);
1881 wpa_hexdump_buf(MSG_DEBUG, "atheros: proberesp_ies",
1882 params->proberesp_ies);
1883 wpa_hexdump_buf(MSG_DEBUG, "atheros: assocresp_ies",
1884 params->assocresp_ies);
1885
1886 return 0;
1887}
1888
Dmitry Shmidt04949592012-07-19 12:16:46 -07001889
1890#ifdef CONFIG_IEEE80211R
1891
1892static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
1893 int noack)
1894{
1895 struct atheros_driver_data *drv = priv;
1896 u8 buf[1510];
1897 const struct ieee80211_mgmt *mgmt;
1898 struct ieee80211req_mgmtbuf *mgmt_frm;
1899
1900 mgmt = (const struct ieee80211_mgmt *) frm;
1901 wpa_printf(MSG_DEBUG, "%s frmlen = %lu " MACSTR, __func__,
1902 (unsigned long) data_len, MAC2STR(mgmt->da));
1903 mgmt_frm = (struct ieee80211req_mgmtbuf *) buf;
1904 memcpy(mgmt_frm->macaddr, (u8 *)mgmt->da, IEEE80211_ADDR_LEN);
1905 mgmt_frm->buflen = data_len;
1906 if (&mgmt_frm->buf[0] + data_len > buf + sizeof(buf)) {
1907 wpa_printf(MSG_INFO, "atheros: Too long frame for "
1908 "atheros_send_mgmt (%u)", (unsigned int) data_len);
1909 return -1;
1910 }
1911 os_memcpy(&mgmt_frm->buf[0], frm, data_len);
1912 return set80211priv(drv, IEEE80211_IOCTL_SEND_MGMT, mgmt_frm,
1913 sizeof(struct ieee80211req_mgmtbuf) + data_len);
1914}
1915
1916
1917static int atheros_add_tspec(void *priv, const u8 *addr, u8 *tspec_ie,
1918 size_t tspec_ielen)
1919{
1920 struct atheros_driver_data *drv = priv;
1921 int retv;
1922 struct ieee80211req_res req;
1923 struct ieee80211req_res_addts *addts = &req.u.addts;
1924
1925 wpa_printf(MSG_DEBUG, "%s", __func__);
1926 req.type = IEEE80211_RESREQ_ADDTS;
1927 os_memcpy(&req.macaddr[0], addr, IEEE80211_ADDR_LEN);
1928 os_memcpy(addts->tspecie, tspec_ie, tspec_ielen);
1929 retv = set80211priv(drv, IEEE80211_IOCTL_RES_REQ, &req,
1930 sizeof(struct ieee80211req_res));
1931 if (retv < 0) {
1932 wpa_printf(MSG_DEBUG, "%s IEEE80211_IOCTL_RES_REQ FAILED "
1933 "retv = %d", __func__, retv);
1934 return -1;
1935 }
1936 os_memcpy(tspec_ie, addts->tspecie, tspec_ielen);
1937 return addts->status;
1938}
1939
1940
1941static int atheros_add_sta_node(void *priv, const u8 *addr, u16 auth_alg)
1942{
1943 struct atheros_driver_data *drv = priv;
1944 struct ieee80211req_res req;
1945 struct ieee80211req_res_addnode *addnode = &req.u.addnode;
1946
1947 wpa_printf(MSG_DEBUG, "%s", __func__);
1948 req.type = IEEE80211_RESREQ_ADDNODE;
1949 os_memcpy(&req.macaddr[0], addr, IEEE80211_ADDR_LEN);
1950 addnode->auth_alg = auth_alg;
1951 return set80211priv(drv, IEEE80211_IOCTL_RES_REQ, &req,
1952 sizeof(struct ieee80211req_res));
1953}
1954
1955#endif /* CONFIG_IEEE80211R */
1956
1957
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001958/* Use only to set a big param, get will not work. */
1959static int
1960set80211big(struct atheros_driver_data *drv, int op, const void *data, int len)
1961{
1962 struct iwreq iwr;
1963
1964 os_memset(&iwr, 0, sizeof(iwr));
1965 os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
1966
1967 iwr.u.data.pointer = (void *) data;
1968 iwr.u.data.length = len;
1969 iwr.u.data.flags = op;
1970 wpa_printf(MSG_DEBUG, "%s: op=0x%x=%d (%s) len=0x%x",
1971 __func__, op, op, athr_get_param_name(op), len);
1972
1973 if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr) < 0) {
1974 wpa_printf(MSG_DEBUG, "%s: op=0x%x (%s) subop=0x%x=%d "
1975 "value=0x%x,0x%x failed: %d (%s)",
1976 __func__, op, athr_get_ioctl_name(op), iwr.u.mode,
1977 iwr.u.mode, iwr.u.data.length,
1978 iwr.u.data.flags, errno, strerror(errno));
1979 return -1;
1980 }
1981 return 0;
1982}
1983
1984
1985static int atheros_send_action(void *priv, unsigned int freq,
1986 unsigned int wait,
1987 const u8 *dst, const u8 *src,
1988 const u8 *bssid,
1989 const u8 *data, size_t data_len, int no_cck)
1990{
1991 struct atheros_driver_data *drv = priv;
1992 struct ieee80211_p2p_send_action *act;
1993 int res;
1994
1995 act = os_zalloc(sizeof(*act) + data_len);
1996 if (act == NULL)
1997 return -1;
1998 act->freq = freq;
1999 os_memcpy(act->dst_addr, dst, ETH_ALEN);
2000 os_memcpy(act->src_addr, src, ETH_ALEN);
2001 os_memcpy(act->bssid, bssid, ETH_ALEN);
2002 os_memcpy(act + 1, data, data_len);
2003 wpa_printf(MSG_DEBUG, "%s: freq=%d, wait=%u, dst=" MACSTR ", src="
2004 MACSTR ", bssid=" MACSTR,
2005 __func__, act->freq, wait, MAC2STR(act->dst_addr),
2006 MAC2STR(act->src_addr), MAC2STR(act->bssid));
2007 wpa_hexdump(MSG_MSGDUMP, "athr: act", (u8 *) act, sizeof(*act));
2008 wpa_hexdump(MSG_MSGDUMP, "athr: data", data, data_len);
2009
2010 res = set80211big(drv, IEEE80211_IOC_P2P_SEND_ACTION,
2011 act, sizeof(*act) + data_len);
2012 os_free(act);
2013 return res;
2014}
2015
2016
Dmitry Shmidt56052862013-10-04 10:23:25 -07002017#if defined(CONFIG_WNM) && defined(IEEE80211_APPIE_FRAME_WNM)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002018static int athr_wnm_tfs(struct atheros_driver_data *drv, const u8* peer,
2019 u8 *ie, u16 *len, enum wnm_oper oper)
2020{
2021#define IEEE80211_APPIE_MAX 1024 /* max appie buffer size */
2022 u8 buf[IEEE80211_APPIE_MAX];
2023 struct ieee80211req_getset_appiebuf *tfs_ie;
2024 u16 val;
2025
2026 wpa_printf(MSG_DEBUG, "atheros: ifname=%s, WNM TFS IE oper=%d " MACSTR,
2027 drv->iface, oper, MAC2STR(peer));
2028
2029 switch (oper) {
2030 case WNM_SLEEP_TFS_REQ_IE_SET:
2031 if (*len > IEEE80211_APPIE_MAX -
2032 sizeof(struct ieee80211req_getset_appiebuf)) {
2033 wpa_printf(MSG_DEBUG, "TFS Req IE(s) too large");
2034 return -1;
2035 }
2036 tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
2037 tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
2038 tfs_ie->app_buflen = ETH_ALEN + 2 + 2 + *len;
2039
2040 /* Command header for driver */
2041 os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
2042 val = oper;
2043 os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
2044 val = *len;
2045 os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
2046
2047 /* copy the ie */
2048 os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2 + 2, ie, *len);
2049
2050 if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie,
2051 IEEE80211_APPIE_MAX)) {
2052 wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: "
2053 "%s", __func__, strerror(errno));
2054 return -1;
2055 }
2056 break;
2057 case WNM_SLEEP_TFS_RESP_IE_ADD:
2058 tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
2059 tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
2060 tfs_ie->app_buflen = IEEE80211_APPIE_MAX -
2061 sizeof(struct ieee80211req_getset_appiebuf);
2062 /* Command header for driver */
2063 os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
2064 val = oper;
2065 os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
2066 val = 0;
2067 os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
2068
2069 if (set80211priv(drv, IEEE80211_IOCTL_GET_APPIEBUF, tfs_ie,
2070 IEEE80211_APPIE_MAX)) {
2071 wpa_printf(MSG_DEBUG, "%s: Failed to get WNM TFS IE: "
2072 "%s", __func__, strerror(errno));
2073 return -1;
2074 }
2075
2076 *len = tfs_ie->app_buflen;
2077 os_memcpy(ie, &(tfs_ie->app_buf[0]), *len);
2078 wpa_printf(MSG_DEBUG, "atheros: %c len=%d", tfs_ie->app_buf[0],
2079 *len);
2080 break;
2081 case WNM_SLEEP_TFS_RESP_IE_NONE:
2082 *len = 0;
2083 break;
2084 case WNM_SLEEP_TFS_IE_DEL:
2085 tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
2086 tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
2087 tfs_ie->app_buflen = IEEE80211_APPIE_MAX -
2088 sizeof(struct ieee80211req_getset_appiebuf);
2089 /* Command header for driver */
2090 os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
2091 val = oper;
2092 os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
2093 val = 0;
2094 os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
2095
2096 if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie,
2097 IEEE80211_APPIE_MAX)) {
2098 wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: "
2099 "%s", __func__, strerror(errno));
2100 return -1;
2101 }
2102 break;
2103 default:
2104 wpa_printf(MSG_DEBUG, "Unsupported TFS oper %d", oper);
2105 break;
2106 }
2107
2108 return 0;
2109}
2110
2111
2112static int atheros_wnm_sleep(struct atheros_driver_data *drv,
2113 const u8 *peer, enum wnm_oper oper)
2114{
2115 u8 *data, *pos;
2116 size_t dlen;
2117 int ret;
2118 u16 val;
2119
2120 wpa_printf(MSG_DEBUG, "atheros: WNM-Sleep Oper %d, " MACSTR,
2121 oper, MAC2STR(peer));
2122
2123 dlen = ETH_ALEN + 2 + 2;
2124 data = os_malloc(dlen);
2125 if (data == NULL)
2126 return -1;
2127
2128 /* Command header for driver */
2129 pos = data;
2130 os_memcpy(pos, peer, ETH_ALEN);
2131 pos += ETH_ALEN;
2132
2133 val = oper;
2134 os_memcpy(pos, &val, 2);
2135 pos += 2;
2136
2137 val = 0;
2138 os_memcpy(pos, &val, 2);
2139
2140 ret = atheros_set_wps_ie(drv, data, dlen, IEEE80211_APPIE_FRAME_WNM);
2141
2142 os_free(data);
2143
2144 return ret;
2145}
2146
2147
2148static int atheros_wnm_oper(void *priv, enum wnm_oper oper, const u8 *peer,
2149 u8 *buf, u16 *buf_len)
2150{
2151 struct atheros_driver_data *drv = priv;
2152
2153 switch (oper) {
2154 case WNM_SLEEP_ENTER_CONFIRM:
2155 case WNM_SLEEP_ENTER_FAIL:
2156 case WNM_SLEEP_EXIT_CONFIRM:
2157 case WNM_SLEEP_EXIT_FAIL:
2158 return atheros_wnm_sleep(drv, peer, oper);
2159 case WNM_SLEEP_TFS_REQ_IE_SET:
2160 case WNM_SLEEP_TFS_RESP_IE_ADD:
2161 case WNM_SLEEP_TFS_RESP_IE_NONE:
2162 case WNM_SLEEP_TFS_IE_DEL:
2163 return athr_wnm_tfs(drv, peer, buf, buf_len, oper);
2164 default:
2165 wpa_printf(MSG_DEBUG, "atheros: Unsupported WNM operation %d",
2166 oper);
2167 return -1;
2168 }
2169}
Dmitry Shmidt56052862013-10-04 10:23:25 -07002170#endif /* CONFIG_WNM && IEEE80211_APPIE_FRAME_WNM */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002171
2172
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002173const struct wpa_driver_ops wpa_driver_atheros_ops = {
2174 .name = "atheros",
2175 .hapd_init = atheros_init,
2176 .hapd_deinit = atheros_deinit,
2177 .set_ieee8021x = atheros_set_ieee8021x,
2178 .set_privacy = atheros_set_privacy,
2179 .set_key = atheros_set_key,
2180 .get_seqnum = atheros_get_seqnum,
2181 .flush = atheros_flush,
2182 .set_generic_elem = atheros_set_opt_ie,
2183 .sta_set_flags = atheros_sta_set_flags,
2184 .read_sta_data = atheros_read_sta_driver_data,
2185 .hapd_send_eapol = atheros_send_eapol,
2186 .sta_disassoc = atheros_sta_disassoc,
2187 .sta_deauth = atheros_sta_deauth,
2188 .hapd_set_ssid = atheros_set_ssid,
2189 .hapd_get_ssid = atheros_get_ssid,
2190 .set_countermeasures = atheros_set_countermeasures,
2191 .sta_clear_stats = atheros_sta_clear_stats,
2192 .commit = atheros_commit,
2193 .set_ap_wps_ie = atheros_set_ap_wps_ie,
Jouni Malinen75ecf522011-06-27 15:19:46 -07002194 .set_authmode = atheros_set_authmode,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002195 .set_ap = atheros_set_ap,
Dmitry Shmidt04949592012-07-19 12:16:46 -07002196#ifdef CONFIG_IEEE80211R
2197 .sta_assoc = atheros_sta_assoc,
2198 .sta_auth = atheros_sta_auth,
2199 .send_mlme = atheros_send_mgmt,
2200 .add_tspec = atheros_add_tspec,
2201 .add_sta_node = atheros_add_sta_node,
2202#endif /* CONFIG_IEEE80211R */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002203 .send_action = atheros_send_action,
Dmitry Shmidt56052862013-10-04 10:23:25 -07002204#if defined(CONFIG_WNM) && defined(IEEE80211_APPIE_FRAME_WNM)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002205 .wnm_oper = atheros_wnm_oper,
Dmitry Shmidt56052862013-10-04 10:23:25 -07002206#endif /* CONFIG_WNM && IEEE80211_APPIE_FRAME_WNM */
Dmitry Shmidt051af732013-10-22 13:52:46 -07002207 .set_qos_map = atheros_set_qos_map,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002208};