blob: eac3ae8af87054084e1a1a5b82f4166beaa0c8c8 [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
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070039/* Avoid conflicting definition from the driver header files with
40 * common/wpa_common.h */
41#undef WPA_OUI_TYPE
42
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070043
44#ifdef CONFIG_WPS
45#include <netpacket/packet.h>
Dmitry Shmidt04949592012-07-19 12:16:46 -070046#endif /* CONFIG_WPS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070047
48#ifndef ETH_P_80211_RAW
49#define ETH_P_80211_RAW 0x0019
50#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070051
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080052#include "linux_wext.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070053
54#include "driver.h"
55#include "eloop.h"
56#include "priv_netlink.h"
57#include "l2_packet/l2_packet.h"
58#include "common/ieee802_11_defs.h"
59#include "netlink.h"
60#include "linux_ioctl.h"
61
62
63struct atheros_driver_data {
64 struct hostapd_data *hapd; /* back pointer */
65
66 char iface[IFNAMSIZ + 1];
67 int ifindex;
68 struct l2_packet_data *sock_xmit; /* raw packet xmit socket */
69 struct l2_packet_data *sock_recv; /* raw packet recv socket */
70 int ioctl_sock; /* socket for ioctl() use */
71 struct netlink_data *netlink;
72 int we_version;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -070073 int fils_en; /* FILS enable/disable in driver */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070074 u8 acct_mac[ETH_ALEN];
75 struct hostap_sta_driver_data acct_data;
76
77 struct l2_packet_data *sock_raw; /* raw 802.11 management frames */
78 struct wpabuf *wpa_ie;
79 struct wpabuf *wps_beacon_ie;
80 struct wpabuf *wps_probe_resp_ie;
Dmitry Shmidt04949592012-07-19 12:16:46 -070081 u8 own_addr[ETH_ALEN];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070082};
83
84static int atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -070085 u16 reason_code);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070086static int atheros_set_privacy(void *priv, int enabled);
87
88static const char * athr_get_ioctl_name(int op)
89{
90 switch (op) {
91 case IEEE80211_IOCTL_SETPARAM:
92 return "SETPARAM";
93 case IEEE80211_IOCTL_GETPARAM:
94 return "GETPARAM";
95 case IEEE80211_IOCTL_SETKEY:
96 return "SETKEY";
97 case IEEE80211_IOCTL_SETWMMPARAMS:
98 return "SETWMMPARAMS";
99 case IEEE80211_IOCTL_DELKEY:
100 return "DELKEY";
101 case IEEE80211_IOCTL_GETWMMPARAMS:
102 return "GETWMMPARAMS";
103 case IEEE80211_IOCTL_SETMLME:
104 return "SETMLME";
105 case IEEE80211_IOCTL_GETCHANINFO:
106 return "GETCHANINFO";
107 case IEEE80211_IOCTL_SETOPTIE:
108 return "SETOPTIE";
109 case IEEE80211_IOCTL_GETOPTIE:
110 return "GETOPTIE";
111 case IEEE80211_IOCTL_ADDMAC:
112 return "ADDMAC";
113 case IEEE80211_IOCTL_DELMAC:
114 return "DELMAC";
115 case IEEE80211_IOCTL_GETCHANLIST:
116 return "GETCHANLIST";
117 case IEEE80211_IOCTL_SETCHANLIST:
118 return "SETCHANLIST";
119 case IEEE80211_IOCTL_KICKMAC:
120 return "KICKMAC";
121 case IEEE80211_IOCTL_CHANSWITCH:
122 return "CHANSWITCH";
123 case IEEE80211_IOCTL_GETMODE:
124 return "GETMODE";
125 case IEEE80211_IOCTL_SETMODE:
126 return "SETMODE";
127 case IEEE80211_IOCTL_GET_APPIEBUF:
128 return "GET_APPIEBUF";
129 case IEEE80211_IOCTL_SET_APPIEBUF:
130 return "SET_APPIEBUF";
131 case IEEE80211_IOCTL_SET_ACPARAMS:
132 return "SET_ACPARAMS";
133 case IEEE80211_IOCTL_FILTERFRAME:
134 return "FILTERFRAME";
135 case IEEE80211_IOCTL_SET_RTPARAMS:
136 return "SET_RTPARAMS";
137 case IEEE80211_IOCTL_SET_MEDENYENTRY:
138 return "SET_MEDENYENTRY";
139 case IEEE80211_IOCTL_GET_MACADDR:
140 return "GET_MACADDR";
141 case IEEE80211_IOCTL_SET_HBRPARAMS:
142 return "SET_HBRPARAMS";
143 case IEEE80211_IOCTL_SET_RXTIMEOUT:
144 return "SET_RXTIMEOUT";
145 case IEEE80211_IOCTL_STA_STATS:
146 return "STA_STATS";
147 case IEEE80211_IOCTL_GETWPAIE:
148 return "GETWPAIE";
149 default:
150 return "??";
151 }
152}
153
154
155static const char * athr_get_param_name(int op)
156{
157 switch (op) {
158 case IEEE80211_IOC_MCASTCIPHER:
159 return "MCASTCIPHER";
160 case IEEE80211_PARAM_MCASTKEYLEN:
161 return "MCASTKEYLEN";
162 case IEEE80211_PARAM_UCASTCIPHERS:
163 return "UCASTCIPHERS";
164 case IEEE80211_PARAM_KEYMGTALGS:
165 return "KEYMGTALGS";
166 case IEEE80211_PARAM_RSNCAPS:
167 return "RSNCAPS";
168 case IEEE80211_PARAM_WPA:
169 return "WPA";
170 case IEEE80211_PARAM_AUTHMODE:
171 return "AUTHMODE";
172 case IEEE80211_PARAM_PRIVACY:
173 return "PRIVACY";
174 case IEEE80211_PARAM_COUNTERMEASURES:
175 return "COUNTERMEASURES";
176 default:
177 return "??";
178 }
179}
180
181
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700182#ifdef CONFIG_FILS
183static int
184get80211param(struct atheros_driver_data *drv, int op, int *data)
185{
186 struct iwreq iwr;
187
188 os_memset(&iwr, 0, sizeof(iwr));
189 os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
190 iwr.u.mode = op;
191
192 if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_GETPARAM, &iwr) < 0)
193 return -1;
194
195 *data = iwr.u.mode;
196 return 0;
197}
198#endif /* CONFIG_FILS */
199
200
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700201static int
202set80211priv(struct atheros_driver_data *drv, int op, void *data, int len)
203{
204 struct iwreq iwr;
205 int do_inline = len < IFNAMSIZ;
206
207 /* Certain ioctls must use the non-inlined method */
208 if (op == IEEE80211_IOCTL_SET_APPIEBUF ||
209 op == IEEE80211_IOCTL_FILTERFRAME)
210 do_inline = 0;
211
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800212 os_memset(&iwr, 0, sizeof(iwr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700213 os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
214 if (do_inline) {
215 /*
216 * Argument data fits inline; put it there.
217 */
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800218 os_memcpy(iwr.u.name, data, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700219 } else {
220 /*
221 * Argument data too big for inline transfer; setup a
222 * parameter block instead; the kernel will transfer
223 * the data for the driver.
224 */
225 iwr.u.data.pointer = data;
226 iwr.u.data.length = len;
227 }
228
229 if (ioctl(drv->ioctl_sock, op, &iwr) < 0) {
230 wpa_printf(MSG_DEBUG, "atheros: %s: %s: ioctl op=0x%x "
231 "(%s) len=%d failed: %d (%s)",
232 __func__, drv->iface, op,
233 athr_get_ioctl_name(op),
234 len, errno, strerror(errno));
235 return -1;
236 }
237 return 0;
238}
239
240static int
241set80211param(struct atheros_driver_data *drv, int op, int arg)
242{
243 struct iwreq iwr;
244
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800245 os_memset(&iwr, 0, sizeof(iwr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700246 os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
247 iwr.u.mode = op;
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800248 os_memcpy(iwr.u.name + sizeof(__u32), &arg, sizeof(arg));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700249
250 if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800251 wpa_printf(MSG_INFO,
252 "%s: %s: Failed to set parameter (op %d (%s) arg %d): ioctl[IEEE80211_IOCTL_SETPARAM]: %s",
253 __func__, drv->iface, op, athr_get_param_name(op),
254 arg, strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700255 return -1;
256 }
257 return 0;
258}
259
260#ifndef CONFIG_NO_STDOUT_DEBUG
261static const char *
262ether_sprintf(const u8 *addr)
263{
264 static char buf[sizeof(MACSTR)];
265
266 if (addr != NULL)
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800267 os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700268 else
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800269 os_snprintf(buf, sizeof(buf), MACSTR, 0, 0, 0, 0, 0, 0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700270 return buf;
271}
272#endif /* CONFIG_NO_STDOUT_DEBUG */
273
274/*
275 * Configure WPA parameters.
276 */
277static int
278atheros_configure_wpa(struct atheros_driver_data *drv,
279 struct wpa_bss_params *params)
280{
281 int v;
282
283 switch (params->wpa_group) {
284 case WPA_CIPHER_CCMP:
285 v = IEEE80211_CIPHER_AES_CCM;
286 break;
Dmitry Shmidt09f57ba2014-06-10 16:07:13 -0700287#ifdef ATH_GCM_SUPPORT
288 case WPA_CIPHER_CCMP_256:
289 v = IEEE80211_CIPHER_AES_CCM_256;
290 break;
291 case WPA_CIPHER_GCMP:
292 v = IEEE80211_CIPHER_AES_GCM;
293 break;
294 case WPA_CIPHER_GCMP_256:
295 v = IEEE80211_CIPHER_AES_GCM_256;
296 break;
297#endif /* ATH_GCM_SUPPORT */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700298 case WPA_CIPHER_TKIP:
299 v = IEEE80211_CIPHER_TKIP;
300 break;
301 case WPA_CIPHER_WEP104:
302 v = IEEE80211_CIPHER_WEP;
303 break;
304 case WPA_CIPHER_WEP40:
305 v = IEEE80211_CIPHER_WEP;
306 break;
307 case WPA_CIPHER_NONE:
308 v = IEEE80211_CIPHER_NONE;
309 break;
310 default:
311 wpa_printf(MSG_ERROR, "Unknown group key cipher %u",
312 params->wpa_group);
313 return -1;
314 }
315 wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v);
316 if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800317 wpa_printf(MSG_INFO, "Unable to set group key cipher to %u", v);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700318 return -1;
319 }
320 if (v == IEEE80211_CIPHER_WEP) {
321 /* key length is done only for specific ciphers */
322 v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
323 if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800324 wpa_printf(MSG_INFO,
325 "Unable to set group key length to %u", v);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700326 return -1;
327 }
328 }
329
330 v = 0;
331 if (params->wpa_pairwise & WPA_CIPHER_CCMP)
332 v |= 1<<IEEE80211_CIPHER_AES_CCM;
Dmitry Shmidt09f57ba2014-06-10 16:07:13 -0700333#ifdef ATH_GCM_SUPPORT
334 if (params->wpa_pairwise & WPA_CIPHER_CCMP_256)
335 v |= 1<<IEEE80211_CIPHER_AES_CCM_256;
336 if (params->wpa_pairwise & WPA_CIPHER_GCMP)
337 v |= 1<<IEEE80211_CIPHER_AES_GCM;
338 if (params->wpa_pairwise & WPA_CIPHER_GCMP_256)
339 v |= 1<<IEEE80211_CIPHER_AES_GCM_256;
340#endif /* ATH_GCM_SUPPORT */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700341 if (params->wpa_pairwise & WPA_CIPHER_TKIP)
342 v |= 1<<IEEE80211_CIPHER_TKIP;
343 if (params->wpa_pairwise & WPA_CIPHER_NONE)
344 v |= 1<<IEEE80211_CIPHER_NONE;
345 wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
346 if (set80211param(drv, IEEE80211_PARAM_UCASTCIPHERS, v)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800347 wpa_printf(MSG_INFO,
348 "Unable to set pairwise key ciphers to 0x%x", v);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700349 return -1;
350 }
351
352 wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
353 __func__, params->wpa_key_mgmt);
354 if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS,
355 params->wpa_key_mgmt)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800356 wpa_printf(MSG_INFO,
357 "Unable to set key management algorithms to 0x%x",
358 params->wpa_key_mgmt);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700359 return -1;
360 }
361
362 v = 0;
363 if (params->rsn_preauth)
364 v |= BIT(0);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700365 if (params->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
366 v |= BIT(7);
367 if (params->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
368 v |= BIT(6);
369 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700370
Dmitry Shmidt4530cfd2012-09-09 15:20:40 -0700371 wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", __func__, v);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700372 if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800373 wpa_printf(MSG_INFO, "Unable to set RSN capabilities to 0x%x",
374 v);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700375 return -1;
376 }
377
378 wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa);
379 if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800380 wpa_printf(MSG_INFO, "Unable to set WPA to %u", params->wpa);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700381 return -1;
382 }
383 return 0;
384}
385
386static int
387atheros_set_ieee8021x(void *priv, struct wpa_bss_params *params)
388{
389 struct atheros_driver_data *drv = priv;
390
391 wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled);
392
393 if (!params->enabled) {
394 /* XXX restore state */
395 if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
396 IEEE80211_AUTH_AUTO) < 0)
397 return -1;
398 /* IEEE80211_AUTH_AUTO ends up enabling Privacy; clear that */
399 return atheros_set_privacy(drv, 0);
400 }
401 if (!params->wpa && !params->ieee802_1x) {
Dmitry Shmidt54605472013-11-08 11:10:19 -0800402 wpa_printf(MSG_WARNING, "No 802.1X or WPA enabled!");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700403 return -1;
404 }
405 if (params->wpa && atheros_configure_wpa(drv, params) != 0) {
Dmitry Shmidt54605472013-11-08 11:10:19 -0800406 wpa_printf(MSG_WARNING, "Error configuring WPA state!");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700407 return -1;
408 }
409 if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
410 (params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
Dmitry Shmidt54605472013-11-08 11:10:19 -0800411 wpa_printf(MSG_WARNING, "Error enabling WPA/802.1X!");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700412 return -1;
413 }
414
415 return 0;
416}
417
418static int
419atheros_set_privacy(void *priv, int enabled)
420{
421 struct atheros_driver_data *drv = priv;
422
423 wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
424
425 return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled);
426}
427
428static int
429atheros_set_sta_authorized(void *priv, const u8 *addr, int authorized)
430{
431 struct atheros_driver_data *drv = priv;
432 struct ieee80211req_mlme mlme;
433 int ret;
434
435 wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d",
436 __func__, ether_sprintf(addr), authorized);
437
438 if (authorized)
439 mlme.im_op = IEEE80211_MLME_AUTHORIZE;
440 else
441 mlme.im_op = IEEE80211_MLME_UNAUTHORIZE;
442 mlme.im_reason = 0;
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800443 os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700444 ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
445 if (ret < 0) {
446 wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR,
447 __func__, authorized ? "" : "un", MAC2STR(addr));
448 }
449
450 return ret;
451}
452
453static int
454atheros_sta_set_flags(void *priv, const u8 *addr,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -0800455 unsigned int total_flags, unsigned int flags_or,
456 unsigned int flags_and)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700457{
458 /* For now, only support setting Authorized flag */
459 if (flags_or & WPA_STA_AUTHORIZED)
460 return atheros_set_sta_authorized(priv, addr, 1);
461 if (!(flags_and & WPA_STA_AUTHORIZED))
462 return atheros_set_sta_authorized(priv, addr, 0);
463 return 0;
464}
465
466static int
467atheros_del_key(void *priv, const u8 *addr, int key_idx)
468{
469 struct atheros_driver_data *drv = priv;
470 struct ieee80211req_del_key wk;
471 int ret;
472
473 wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d",
474 __func__, ether_sprintf(addr), key_idx);
475
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800476 os_memset(&wk, 0, sizeof(wk));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700477 if (addr != NULL) {
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800478 os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700479 wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE;
480 } else {
481 wk.idk_keyix = key_idx;
482 }
483
484 ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk));
485 if (ret < 0) {
486 wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s"
487 " key_idx %d)", __func__, ether_sprintf(addr),
488 key_idx);
489 }
490
491 return ret;
492}
493
494static int
495atheros_set_key(const char *ifname, void *priv, enum wpa_alg alg,
496 const u8 *addr, int key_idx, int set_tx, const u8 *seq,
497 size_t seq_len, const u8 *key, size_t key_len)
498{
499 struct atheros_driver_data *drv = priv;
500 struct ieee80211req_key wk;
501 u_int8_t cipher;
502 int ret;
503
504 if (alg == WPA_ALG_NONE)
505 return atheros_del_key(drv, addr, key_idx);
506
507 wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d",
508 __func__, alg, ether_sprintf(addr), key_idx);
509
510 switch (alg) {
511 case WPA_ALG_WEP:
512 cipher = IEEE80211_CIPHER_WEP;
513 break;
514 case WPA_ALG_TKIP:
515 cipher = IEEE80211_CIPHER_TKIP;
516 break;
517 case WPA_ALG_CCMP:
518 cipher = IEEE80211_CIPHER_AES_CCM;
519 break;
Dmitry Shmidt09f57ba2014-06-10 16:07:13 -0700520#ifdef ATH_GCM_SUPPORT
521 case WPA_ALG_CCMP_256:
522 cipher = IEEE80211_CIPHER_AES_CCM_256;
523 break;
524 case WPA_ALG_GCMP:
525 cipher = IEEE80211_CIPHER_AES_GCM;
526 break;
527 case WPA_ALG_GCMP_256:
528 cipher = IEEE80211_CIPHER_AES_GCM_256;
529 break;
530#endif /* ATH_GCM_SUPPORT */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700531 case WPA_ALG_IGTK:
532 cipher = IEEE80211_CIPHER_AES_CMAC;
533 break;
Dmitry Shmidt09f57ba2014-06-10 16:07:13 -0700534#ifdef ATH_GCM_SUPPORT
535 case WPA_ALG_BIP_CMAC_256:
536 cipher = IEEE80211_CIPHER_AES_CMAC_256;
537 break;
538 case WPA_ALG_BIP_GMAC_128:
539 cipher = IEEE80211_CIPHER_AES_GMAC;
540 break;
541 case WPA_ALG_BIP_GMAC_256:
542 cipher = IEEE80211_CIPHER_AES_GMAC_256;
543 break;
544#endif /* ATH_GCM_SUPPORT */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700545 default:
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800546 wpa_printf(MSG_INFO, "%s: unknown/unsupported algorithm %d",
547 __func__, alg);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700548 return -1;
549 }
550
551 if (key_len > sizeof(wk.ik_keydata)) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800552 wpa_printf(MSG_INFO, "%s: key length %lu too big", __func__,
553 (unsigned long) key_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700554 return -3;
555 }
556
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800557 os_memset(&wk, 0, sizeof(wk));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700558 wk.ik_type = cipher;
559 wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT;
560 if (addr == NULL || is_broadcast_ether_addr(addr)) {
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800561 os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700562 wk.ik_keyix = key_idx;
563 if (set_tx)
564 wk.ik_flags |= IEEE80211_KEY_DEFAULT;
565 } else {
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800566 os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700567 wk.ik_keyix = IEEE80211_KEYIX_NONE;
568 }
569 wk.ik_keylen = key_len;
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800570 os_memcpy(wk.ik_keydata, key, key_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700571
572 ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk));
573 if (ret < 0) {
574 wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s"
575 " key_idx %d alg %d key_len %lu set_tx %d)",
576 __func__, ether_sprintf(wk.ik_macaddr), key_idx,
577 alg, (unsigned long) key_len, set_tx);
578 }
579
580 return ret;
581}
582
583
584static int
585atheros_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
586 u8 *seq)
587{
588 struct atheros_driver_data *drv = priv;
589 struct ieee80211req_key wk;
590
591 wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
592 __func__, ether_sprintf(addr), idx);
593
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800594 os_memset(&wk, 0, sizeof(wk));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700595 if (addr == NULL)
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800596 os_memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700597 else
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800598 os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700599 wk.ik_keyix = idx;
600
601 if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) {
602 wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data "
603 "(addr " MACSTR " key_idx %d)",
604 __func__, MAC2STR(wk.ik_macaddr), idx);
605 return -1;
606 }
607
608#ifdef WORDS_BIGENDIAN
609 {
610 /*
611 * wk.ik_keytsc is in host byte order (big endian), need to
612 * swap it to match with the byte order used in WPA.
613 */
614 int i;
615#ifndef WPA_KEY_RSC_LEN
616#define WPA_KEY_RSC_LEN 8
617#endif
618 u8 tmp[WPA_KEY_RSC_LEN];
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800619 os_memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700620 for (i = 0; i < WPA_KEY_RSC_LEN; i++) {
621 seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1];
622 }
623 }
624#else /* WORDS_BIGENDIAN */
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800625 os_memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700626#endif /* WORDS_BIGENDIAN */
627 return 0;
628}
629
630
631static int
632atheros_flush(void *priv)
633{
634 u8 allsta[IEEE80211_ADDR_LEN];
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800635 os_memset(allsta, 0xff, IEEE80211_ADDR_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700636 return atheros_sta_deauth(priv, NULL, allsta,
637 IEEE80211_REASON_AUTH_LEAVE);
638}
639
640
641static int
642atheros_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
643 const u8 *addr)
644{
645 struct atheros_driver_data *drv = priv;
646 struct ieee80211req_sta_stats stats;
647
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800648 os_memset(data, 0, sizeof(*data));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700649
650 /*
651 * Fetch statistics for station from the system.
652 */
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800653 os_memset(&stats, 0, sizeof(stats));
654 os_memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700655 if (set80211priv(drv, IEEE80211_IOCTL_STA_STATS,
656 &stats, sizeof(stats))) {
657 wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr "
658 MACSTR ")", __func__, MAC2STR(addr));
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800659 if (os_memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
660 os_memcpy(data, &drv->acct_data, sizeof(*data));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700661 return 0;
662 }
663
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800664 wpa_printf(MSG_INFO,
665 "Failed to get station stats information element");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700666 return -1;
667 }
668
669 data->rx_packets = stats.is_stats.ns_rx_data;
670 data->rx_bytes = stats.is_stats.ns_rx_bytes;
671 data->tx_packets = stats.is_stats.ns_tx_data;
672 data->tx_bytes = stats.is_stats.ns_tx_bytes;
673 return 0;
674}
675
676
677static int
678atheros_sta_clear_stats(void *priv, const u8 *addr)
679{
680 struct atheros_driver_data *drv = priv;
681 struct ieee80211req_mlme mlme;
682 int ret;
683
684 wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr));
685
686 mlme.im_op = IEEE80211_MLME_CLEAR_STATS;
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800687 os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700688 ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
689 sizeof(mlme));
690 if (ret < 0) {
691 wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr "
692 MACSTR ")", __func__, MAC2STR(addr));
693 }
694
695 return ret;
696}
697
698
699static int
700atheros_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
701{
702 struct atheros_driver_data *drv = priv;
703 u8 buf[512];
704 struct ieee80211req_getset_appiebuf *app_ie;
705
706 wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
707 (unsigned long) ie_len);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800708 wpa_hexdump(MSG_DEBUG, "atheros: set_generic_elem", ie, ie_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700709
710 wpabuf_free(drv->wpa_ie);
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700711 if (ie)
712 drv->wpa_ie = wpabuf_alloc_copy(ie, ie_len);
713 else
714 drv->wpa_ie = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700715
716 app_ie = (struct ieee80211req_getset_appiebuf *) buf;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700717 if (ie)
718 os_memcpy(&(app_ie->app_buf[0]), ie, ie_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700719 app_ie->app_buflen = ie_len;
720
721 app_ie->app_frmtype = IEEE80211_APPIE_FRAME_BEACON;
722
723 /* append WPS IE for Beacon */
724 if (drv->wps_beacon_ie != NULL) {
725 os_memcpy(&(app_ie->app_buf[ie_len]),
726 wpabuf_head(drv->wps_beacon_ie),
727 wpabuf_len(drv->wps_beacon_ie));
728 app_ie->app_buflen = ie_len + wpabuf_len(drv->wps_beacon_ie);
729 }
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800730 wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(Beacon)",
731 app_ie->app_buf, app_ie->app_buflen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700732 set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie,
733 sizeof(struct ieee80211req_getset_appiebuf) +
734 app_ie->app_buflen);
735
736 /* append WPS IE for Probe Response */
737 app_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_RESP;
738 if (drv->wps_probe_resp_ie != NULL) {
739 os_memcpy(&(app_ie->app_buf[ie_len]),
740 wpabuf_head(drv->wps_probe_resp_ie),
741 wpabuf_len(drv->wps_probe_resp_ie));
742 app_ie->app_buflen = ie_len +
743 wpabuf_len(drv->wps_probe_resp_ie);
744 } else
745 app_ie->app_buflen = ie_len;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -0800746 wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(ProbeResp)",
747 app_ie->app_buf, app_ie->app_buflen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700748 set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie,
749 sizeof(struct ieee80211req_getset_appiebuf) +
750 app_ie->app_buflen);
751 return 0;
752}
753
754static int
755atheros_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -0700756 u16 reason_code)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700757{
758 struct atheros_driver_data *drv = priv;
759 struct ieee80211req_mlme mlme;
760 int ret;
761
762 wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
763 __func__, ether_sprintf(addr), reason_code);
764
765 mlme.im_op = IEEE80211_MLME_DEAUTH;
766 mlme.im_reason = reason_code;
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800767 os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700768 ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
769 if (ret < 0) {
770 wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR
771 " reason %d)",
772 __func__, MAC2STR(addr), reason_code);
773 }
774
775 return ret;
776}
777
778static int
779atheros_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
Hai Shalom81f62d82019-07-22 12:10:00 -0700780 u16 reason_code)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700781{
782 struct atheros_driver_data *drv = priv;
783 struct ieee80211req_mlme mlme;
784 int ret;
785
786 wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
787 __func__, ether_sprintf(addr), reason_code);
788
789 mlme.im_op = IEEE80211_MLME_DISASSOC;
790 mlme.im_reason = reason_code;
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800791 os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700792 ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
793 if (ret < 0) {
794 wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr "
795 MACSTR " reason %d)",
796 __func__, MAC2STR(addr), reason_code);
797 }
798
799 return ret;
800}
801
Dmitry Shmidt051af732013-10-22 13:52:46 -0700802static int atheros_set_qos_map(void *ctx, const u8 *qos_map_set,
803 u8 qos_map_set_len)
804{
805#ifdef CONFIG_ATHEROS_QOS_MAP
806 struct atheros_driver_data *drv = ctx;
807 struct ieee80211req_athdbg req;
808 struct ieee80211_qos_map *qos_map = &req.data.qos_map;
809 struct iwreq iwr;
810 int i, up_start;
811
812 if (qos_map_set_len < 16 || qos_map_set_len > 58 ||
813 qos_map_set_len & 1) {
814 wpa_printf(MSG_ERROR, "Invalid QoS Map");
815 return -1;
816 } else {
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -0800817 os_memset(&req, 0, sizeof(struct ieee80211req_athdbg));
Dmitry Shmidt051af732013-10-22 13:52:46 -0700818 req.cmd = IEEE80211_DBGREQ_SETQOSMAPCONF;
819 os_memset(&iwr, 0, sizeof(iwr));
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700820 os_strlcpy(iwr.ifr_name, drv->iface, sizeof(iwr.ifr_name));
Dmitry Shmidt051af732013-10-22 13:52:46 -0700821 iwr.u.data.pointer = (void *) &req;
822 iwr.u.data.length = sizeof(struct ieee80211req_athdbg);
823 }
824
825 qos_map->valid = 1;
826 qos_map->num_dscp_except = (qos_map_set_len - 16) / 2;
827 if (qos_map->num_dscp_except) {
828 for (i = 0; i < qos_map->num_dscp_except; i++) {
829 qos_map->dscp_exception[i].dscp = qos_map_set[i * 2];
830 qos_map->dscp_exception[i].up = qos_map_set[i * 2 + 1];
831 }
832 }
833
834 up_start = qos_map_set_len - 16;
835 for (i = 0; i < IEEE80211_MAX_QOS_UP_RANGE; i++) {
836 qos_map->up[i].low = qos_map_set[up_start + (i * 2)];
837 qos_map->up[i].high = qos_map_set[up_start + (i * 2) + 1];
838 }
839
840 if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_DBGREQ, &iwr) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800841 wpa_printf(MSG_ERROR,
842 "%s: %s: Failed to set QoS Map: ioctl[IEEE80211_IOCTL_DBGREQ]: %s",
843 __func__, drv->iface, strerror(errno));
Dmitry Shmidt051af732013-10-22 13:52:46 -0700844 return -1;
845 }
846#endif /* CONFIG_ATHEROS_QOS_MAP */
847
848 return 0;
849}
850
Hai Shalomc3565922019-10-28 11:58:20 -0700851
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800852static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
853 size_t len)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700854{
855 struct atheros_driver_data *drv = ctx;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700856 const struct ieee80211_mgmt *mgmt;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800857 union wpa_event_data event;
858 u16 fc, stype;
859 int ielen;
860 const u8 *iebuf;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700861
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700862 if (len < IEEE80211_HDRLEN)
863 return;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800864
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700865 mgmt = (const struct ieee80211_mgmt *) buf;
866
867 fc = le_to_host16(mgmt->frame_control);
868
869 if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
870 return;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800871
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700872 stype = WLAN_FC_GET_STYPE(fc);
873
874 wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype,
875 (int) len);
876
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800877 if (stype == WLAN_FC_STYPE_PROBE_REQ) {
Dmitry Shmidte4663042016-04-04 10:07:49 -0700878 if (len < IEEE80211_HDRLEN)
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800879 return;
880
881 os_memset(&event, 0, sizeof(event));
882 event.rx_probe_req.sa = mgmt->sa;
883 event.rx_probe_req.da = mgmt->da;
884 event.rx_probe_req.bssid = mgmt->bssid;
Dmitry Shmidte4663042016-04-04 10:07:49 -0700885 event.rx_probe_req.ie = buf + IEEE80211_HDRLEN;
886 event.rx_probe_req.ie_len = len - IEEE80211_HDRLEN;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800887 wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event);
888 return;
889 }
890
Dmitry Shmidt7f2c7532016-08-15 09:48:12 -0700891 if (stype == WLAN_FC_STYPE_ACTION &&
892 (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) == 0 ||
893 is_broadcast_ether_addr(mgmt->bssid))) {
894 os_memset(&event, 0, sizeof(event));
895 event.rx_mgmt.frame = buf;
896 event.rx_mgmt.frame_len = len;
897 wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
898 return;
899 }
900
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700901 if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
902 wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
903 __func__);
904 return;
905 }
906
907 switch (stype) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800908 case WLAN_FC_STYPE_ASSOC_REQ:
909 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req))
910 break;
911 ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
912 iebuf = mgmt->u.assoc_req.variable;
913 drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 0);
914 break;
915 case WLAN_FC_STYPE_REASSOC_REQ:
916 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req))
917 break;
918 ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
919 iebuf = mgmt->u.reassoc_req.variable;
920 drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1);
921 break;
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800922 case WLAN_FC_STYPE_AUTH:
923 if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth))
924 break;
925 os_memset(&event, 0, sizeof(event));
Roshan Pius3a1667e2018-07-03 15:17:14 -0700926 if (le_to_host16(mgmt->u.auth.auth_alg) == WLAN_AUTH_SAE) {
927 event.rx_mgmt.frame = buf;
928 event.rx_mgmt.frame_len = len;
929 wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
930 break;
931 }
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -0800932 os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
933 os_memcpy(event.auth.bssid, mgmt->bssid, ETH_ALEN);
934 event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
935 event.auth.status_code =
936 le_to_host16(mgmt->u.auth.status_code);
937 event.auth.auth_transaction =
938 le_to_host16(mgmt->u.auth.auth_transaction);
939 event.auth.ies = mgmt->u.auth.variable;
940 event.auth.ies_len = len - IEEE80211_HDRLEN -
941 sizeof(mgmt->u.auth);
942 wpa_supplicant_event(drv->hapd, EVENT_AUTH, &event);
943 break;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700944 default:
945 break;
946 }
947}
Hai Shalomc3565922019-10-28 11:58:20 -0700948
Dmitry Shmidt04949592012-07-19 12:16:46 -0700949
950static int atheros_receive_pkt(struct atheros_driver_data *drv)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700951{
952 int ret = 0;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700953 struct ieee80211req_set_filter filt;
954
955 wpa_printf(MSG_DEBUG, "%s Enter", __func__);
Dmitry Shmidt04949592012-07-19 12:16:46 -0700956 filt.app_filterype = 0;
957#ifdef CONFIG_WPS
958 filt.app_filterype |= IEEE80211_FILTER_TYPE_PROBE_REQ;
959#endif /* CONFIG_WPS */
Dmitry Shmidt04949592012-07-19 12:16:46 -0700960 filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ |
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700961 IEEE80211_FILTER_TYPE_AUTH |
962 IEEE80211_FILTER_TYPE_ACTION);
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800963#ifdef CONFIG_WNM
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700964 filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -0800965#endif /* CONFIG_WNM */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700966#ifdef CONFIG_HS20
967 filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
968#endif /* CONFIG_HS20 */
Dmitry Shmidt04949592012-07-19 12:16:46 -0700969 if (filt.app_filterype) {
970 ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
971 sizeof(struct ieee80211req_set_filter));
972 if (ret)
973 return ret;
974 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700975
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700976#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_FILS)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700977 drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW,
978 atheros_raw_receive, drv, 1);
979 if (drv->sock_raw == NULL)
980 return -1;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -0700981#endif /* CONFIG_WPS || CONFIG_IEEE80211R || CONFIG_FILS */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700982 return ret;
983}
984
Dmitry Shmidt04949592012-07-19 12:16:46 -0700985static int atheros_reset_appfilter(struct atheros_driver_data *drv)
986{
987 struct ieee80211req_set_filter filt;
988 filt.app_filterype = 0;
989 return set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
990 sizeof(struct ieee80211req_set_filter));
991}
992
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700993#ifdef CONFIG_WPS
994static int
995atheros_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype)
996{
997 struct atheros_driver_data *drv = priv;
998 u8 buf[512];
999 struct ieee80211req_getset_appiebuf *beac_ie;
1000
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001001 wpa_printf(MSG_DEBUG, "%s buflen = %lu frametype=%u", __func__,
1002 (unsigned long) len, frametype);
1003 wpa_hexdump(MSG_DEBUG, "atheros: IE", ie, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001004
1005 beac_ie = (struct ieee80211req_getset_appiebuf *) buf;
1006 beac_ie->app_frmtype = frametype;
1007 beac_ie->app_buflen = len;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001008 if (ie)
1009 os_memcpy(&(beac_ie->app_buf[0]), ie, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001010
1011 /* append the WPA/RSN IE if it is set already */
1012 if (((frametype == IEEE80211_APPIE_FRAME_BEACON) ||
1013 (frametype == IEEE80211_APPIE_FRAME_PROBE_RESP)) &&
1014 (drv->wpa_ie != NULL)) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001015 wpa_hexdump_buf(MSG_DEBUG, "atheros: Append WPA/RSN IE",
1016 drv->wpa_ie);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001017 os_memcpy(&(beac_ie->app_buf[len]), wpabuf_head(drv->wpa_ie),
1018 wpabuf_len(drv->wpa_ie));
1019 beac_ie->app_buflen += wpabuf_len(drv->wpa_ie);
1020 }
1021
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001022 wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF",
1023 beac_ie->app_buf, beac_ie->app_buflen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001024 return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie,
1025 sizeof(struct ieee80211req_getset_appiebuf) +
1026 beac_ie->app_buflen);
1027}
1028
1029static int
1030atheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
1031 const struct wpabuf *proberesp,
1032 const struct wpabuf *assocresp)
1033{
1034 struct atheros_driver_data *drv = priv;
1035
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001036 wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - beacon", beacon);
1037 wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - proberesp",
1038 proberesp);
1039 wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - assocresp",
1040 assocresp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001041 wpabuf_free(drv->wps_beacon_ie);
1042 drv->wps_beacon_ie = beacon ? wpabuf_dup(beacon) : NULL;
1043 wpabuf_free(drv->wps_probe_resp_ie);
1044 drv->wps_probe_resp_ie = proberesp ? wpabuf_dup(proberesp) : NULL;
1045
1046 atheros_set_wps_ie(priv, assocresp ? wpabuf_head(assocresp) : NULL,
1047 assocresp ? wpabuf_len(assocresp) : 0,
1048 IEEE80211_APPIE_FRAME_ASSOC_RESP);
1049 if (atheros_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL,
1050 beacon ? wpabuf_len(beacon) : 0,
1051 IEEE80211_APPIE_FRAME_BEACON))
1052 return -1;
1053 return atheros_set_wps_ie(priv,
1054 proberesp ? wpabuf_head(proberesp) : NULL,
1055 proberesp ? wpabuf_len(proberesp): 0,
1056 IEEE80211_APPIE_FRAME_PROBE_RESP);
1057}
1058#else /* CONFIG_WPS */
1059#define atheros_set_ap_wps_ie NULL
1060#endif /* CONFIG_WPS */
1061
Dmitry Shmidt04949592012-07-19 12:16:46 -07001062static int
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001063atheros_sta_auth(void *priv, struct wpa_driver_sta_auth_params *params)
Dmitry Shmidt04949592012-07-19 12:16:46 -07001064{
1065 struct atheros_driver_data *drv = priv;
1066 struct ieee80211req_mlme mlme;
1067 int ret;
1068
1069 wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001070 __func__, ether_sprintf(params->addr), params->status);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001071
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001072#ifdef CONFIG_FILS
1073 /* Copy FILS AAD parameters if the driver supports FILS */
1074 if (params->fils_auth && drv->fils_en) {
1075 wpa_printf(MSG_DEBUG, "%s: im_op IEEE80211_MLME_AUTH_FILS",
1076 __func__);
1077 os_memcpy(mlme.fils_aad.ANonce, params->fils_anonce,
1078 IEEE80211_FILS_NONCE_LEN);
1079 os_memcpy(mlme.fils_aad.SNonce, params->fils_snonce,
1080 IEEE80211_FILS_NONCE_LEN);
1081 os_memcpy(mlme.fils_aad.kek, params->fils_kek,
1082 IEEE80211_MAX_WPA_KEK_LEN);
1083 mlme.fils_aad.kek_len = params->fils_kek_len;
1084 mlme.im_op = IEEE80211_MLME_AUTH_FILS;
1085 wpa_hexdump(MSG_DEBUG, "FILS: ANonce",
1086 mlme.fils_aad.ANonce, FILS_NONCE_LEN);
1087 wpa_hexdump(MSG_DEBUG, "FILS: SNonce",
1088 mlme.fils_aad.SNonce, FILS_NONCE_LEN);
1089 wpa_hexdump_key(MSG_DEBUG, "FILS: KEK",
1090 mlme.fils_aad.kek, mlme.fils_aad.kek_len);
1091 } else {
1092 mlme.im_op = IEEE80211_MLME_AUTH;
1093 }
1094#else /* CONFIG_FILS */
Dmitry Shmidt04949592012-07-19 12:16:46 -07001095 mlme.im_op = IEEE80211_MLME_AUTH;
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001096#endif /* CONFIG_FILS */
1097
1098 mlme.im_reason = params->status;
1099 mlme.im_seq = params->seq;
1100 os_memcpy(mlme.im_macaddr, params->addr, IEEE80211_ADDR_LEN);
1101 mlme.im_optie_len = params->len;
1102 if (params->len) {
1103 if (params->len < IEEE80211_MAX_OPT_IE) {
1104 os_memcpy(mlme.im_optie, params->ie, params->len);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001105 } else {
1106 wpa_printf(MSG_DEBUG, "%s: Not enough space to copy "
1107 "opt_ie STA (addr " MACSTR " reason %d, "
1108 "ie_len %d)",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001109 __func__, MAC2STR(params->addr),
1110 params->status, (int) params->len);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001111 return -1;
1112 }
1113 }
1114 ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
1115 if (ret < 0) {
1116 wpa_printf(MSG_DEBUG, "%s: Failed to auth STA (addr " MACSTR
1117 " reason %d)",
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001118 __func__, MAC2STR(params->addr), params->status);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001119 }
1120 return ret;
1121}
1122
1123static int
1124atheros_sta_assoc(void *priv, const u8 *own_addr, const u8 *addr,
1125 int reassoc, u16 status_code, const u8 *ie, size_t len)
1126{
1127 struct atheros_driver_data *drv = priv;
1128 struct ieee80211req_mlme mlme;
1129 int ret;
1130
1131 wpa_printf(MSG_DEBUG, "%s: addr=%s status_code=%d reassoc %d",
1132 __func__, ether_sprintf(addr), status_code, reassoc);
1133
1134 if (reassoc)
1135 mlme.im_op = IEEE80211_MLME_REASSOC;
1136 else
1137 mlme.im_op = IEEE80211_MLME_ASSOC;
1138 mlme.im_reason = status_code;
1139 os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
1140 mlme.im_optie_len = len;
1141 if (len) {
1142 if (len < IEEE80211_MAX_OPT_IE) {
1143 os_memcpy(mlme.im_optie, ie, len);
1144 } else {
1145 wpa_printf(MSG_DEBUG, "%s: Not enough space to copy "
1146 "opt_ie STA (addr " MACSTR " reason %d, "
1147 "ie_len %d)",
1148 __func__, MAC2STR(addr), status_code,
1149 (int) len);
1150 return -1;
1151 }
1152 }
1153 ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
1154 if (ret < 0) {
1155 wpa_printf(MSG_DEBUG, "%s: Failed to assoc STA (addr " MACSTR
1156 " reason %d)",
1157 __func__, MAC2STR(addr), status_code);
1158 }
1159 return ret;
1160}
Hai Shalomc3565922019-10-28 11:58:20 -07001161
Dmitry Shmidt04949592012-07-19 12:16:46 -07001162
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001163static void
1164atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
1165{
1166 struct hostapd_data *hapd = drv->hapd;
1167 struct ieee80211req_wpaie ie;
1168 int ielen = 0;
1169 u8 *iebuf = NULL;
1170
1171 /*
1172 * Fetch negotiated WPA/RSN parameters from the system.
1173 */
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001174 os_memset(&ie, 0, sizeof(ie));
1175 os_memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001176 if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) {
1177 /*
1178 * See ATH_WPS_IE comment in the beginning of the file for a
1179 * possible cause for the failure..
1180 */
1181 wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE: %s",
1182 __func__, strerror(errno));
1183 goto no_ie;
1184 }
1185 wpa_hexdump(MSG_MSGDUMP, "atheros req WPA IE",
1186 ie.wpa_ie, IEEE80211_MAX_OPT_IE);
1187 wpa_hexdump(MSG_MSGDUMP, "atheros req RSN IE",
1188 ie.rsn_ie, IEEE80211_MAX_OPT_IE);
1189#ifdef ATH_WPS_IE
1190 wpa_hexdump(MSG_MSGDUMP, "atheros req WPS IE",
1191 ie.wps_ie, IEEE80211_MAX_OPT_IE);
1192#endif /* ATH_WPS_IE */
1193 iebuf = ie.wpa_ie;
1194 /* atheros seems to return some random data if WPA/RSN IE is not set.
1195 * Assume the IE was not included if the IE type is unknown. */
1196 if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC)
1197 iebuf[1] = 0;
1198 if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) {
1199 /* atheros-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not
1200 * set. This is needed for WPA2. */
1201 iebuf = ie.rsn_ie;
1202 if (iebuf[0] != WLAN_EID_RSN)
1203 iebuf[1] = 0;
1204 }
1205
1206 ielen = iebuf[1];
1207
1208#ifdef ATH_WPS_IE
1209 /* if WPS IE is present, preference is given to WPS */
Hai Shalom021b0b52019-04-10 11:17:58 -07001210 if (ie.wps_ie[0] == WLAN_EID_VENDOR_SPECIFIC && ie.wps_ie[1] > 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001211 iebuf = ie.wps_ie;
1212 ielen = ie.wps_ie[1];
1213 }
1214#endif /* ATH_WPS_IE */
1215
1216 if (ielen == 0)
1217 iebuf = NULL;
1218 else
1219 ielen += 2;
1220
1221no_ie:
1222 drv_event_assoc(hapd, addr, iebuf, ielen, 0);
1223
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001224 if (os_memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001225 /* Cached accounting data is not valid anymore. */
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001226 os_memset(drv->acct_mac, 0, ETH_ALEN);
1227 os_memset(&drv->acct_data, 0, sizeof(drv->acct_data));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001228 }
1229}
1230
1231static void
1232atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
1233 char *custom, char *end)
1234{
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001235#define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001236 wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
1237
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001238 if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001239 char *pos;
1240 u8 addr[ETH_ALEN];
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001241 pos = os_strstr(custom, "addr=");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001242 if (pos == NULL) {
1243 wpa_printf(MSG_DEBUG,
1244 "MLME-MICHAELMICFAILURE.indication "
1245 "without sender address ignored");
1246 return;
1247 }
1248 pos += 5;
1249 if (hwaddr_aton(pos, addr) == 0) {
1250 union wpa_event_data data;
1251 os_memset(&data, 0, sizeof(data));
1252 data.michael_mic_failure.unicast = 1;
1253 data.michael_mic_failure.src = addr;
1254 wpa_supplicant_event(drv->hapd,
1255 EVENT_MICHAEL_MIC_FAILURE, &data);
1256 } else {
1257 wpa_printf(MSG_DEBUG,
1258 "MLME-MICHAELMICFAILURE.indication "
1259 "with invalid MAC address");
1260 }
1261 } else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) {
1262 char *key, *value;
1263 u32 val;
1264 key = custom;
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001265 while ((key = os_strchr(key, '\n')) != NULL) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001266 key++;
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001267 value = os_strchr(key, '=');
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001268 if (value == NULL)
1269 continue;
1270 *value++ = '\0';
1271 val = strtoul(value, NULL, 10);
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001272 if (os_strcmp(key, "mac") == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001273 hwaddr_aton(value, drv->acct_mac);
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001274 else if (os_strcmp(key, "rx_packets") == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001275 drv->acct_data.rx_packets = val;
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001276 else if (os_strcmp(key, "tx_packets") == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001277 drv->acct_data.tx_packets = val;
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001278 else if (os_strcmp(key, "rx_bytes") == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001279 drv->acct_data.rx_bytes = val;
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001280 else if (os_strcmp(key, "tx_bytes") == 0)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001281 drv->acct_data.tx_bytes = val;
1282 key = value;
1283 }
1284#ifdef CONFIG_WPS
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001285 } else if (os_strncmp(custom, "PUSH-BUTTON.indication", 22) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001286 /* Some atheros kernels send push button as a wireless event */
1287 /* PROBLEM! this event is received for ALL BSSs ...
1288 * so all are enabled for WPS... ugh.
1289 */
1290 wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL);
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001291 } else if (os_strncmp(custom, "Manage.prob_req ", 16) == 0) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001292 /*
1293 * Atheros driver uses a hack to pass Probe Request frames as a
1294 * binary data in the custom wireless event. The old way (using
1295 * packet sniffing) didn't work when bridging.
1296 * Format: "Manage.prob_req <frame len>" | zero padding | frame
1297 */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001298 int len = atoi(custom + 16);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001299 if (len < 0 || MGMT_FRAM_TAG_SIZE + len > end - custom) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001300 wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req event "
1301 "length %d", len);
1302 return;
1303 }
1304 atheros_raw_receive(drv, NULL,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001305 (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001306#endif /* CONFIG_WPS */
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001307 } else if (os_strncmp(custom, "Manage.assoc_req ", 17) == 0) {
Dmitry Shmidt04949592012-07-19 12:16:46 -07001308 /* Format: "Manage.assoc_req <frame len>" | zero padding |
1309 * frame */
1310 int len = atoi(custom + 17);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001311 if (len < 0 || MGMT_FRAM_TAG_SIZE + len > end - custom) {
1312 wpa_printf(MSG_DEBUG,
1313 "Invalid Manage.assoc_req event length %d",
1314 len);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001315 return;
1316 }
1317 atheros_raw_receive(drv, NULL,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001318 (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
Hai Shalom74f70d42019-02-11 14:42:39 -08001319 } else if (os_strncmp(custom, "Manage.auth ", 12) == 0) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001320 /* Format: "Manage.auth <frame len>" | zero padding | frame */
Dmitry Shmidt04949592012-07-19 12:16:46 -07001321 int len = atoi(custom + 12);
Hai Shalom74f70d42019-02-11 14:42:39 -08001322 if (len < 0 ||
1323 MGMT_FRAM_TAG_SIZE + len > end - custom) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001324 wpa_printf(MSG_DEBUG,
1325 "Invalid Manage.auth event length %d", len);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001326 return;
1327 }
1328 atheros_raw_receive(drv, NULL,
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001329 (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
Hai Shalom74f70d42019-02-11 14:42:39 -08001330 } else if (os_strncmp(custom, "Manage.action ", 14) == 0) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001331 /* Format: "Manage.assoc_req <frame len>" | zero padding | frame
1332 */
1333 int len = atoi(custom + 14);
1334 if (len < 0 || MGMT_FRAM_TAG_SIZE + len > end - custom) {
1335 wpa_printf(MSG_DEBUG,
1336 "Invalid Manage.action event length %d",
1337 len);
1338 return;
1339 }
1340 atheros_raw_receive(drv, NULL,
1341 (u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001342 }
1343}
1344
Roshan Pius3a1667e2018-07-03 15:17:14 -07001345
1346static void send_action_cb_event(struct atheros_driver_data *drv,
1347 char *data, size_t data_len)
1348{
1349 union wpa_event_data event;
1350 struct ieee80211_send_action_cb *sa;
1351 const struct ieee80211_hdr *hdr;
1352 u16 fc;
1353
1354 if (data_len < sizeof(*sa) + 24) {
1355 wpa_printf(MSG_DEBUG,
1356 "athr: Too short event message (data_len=%d sizeof(*sa)=%d)",
1357 (int) data_len, (int) sizeof(*sa));
1358 wpa_hexdump(MSG_DEBUG, "athr: Short event message",
1359 data, data_len);
1360 return;
1361 }
1362
1363 sa = (struct ieee80211_send_action_cb *) data;
1364
1365 hdr = (const struct ieee80211_hdr *) (sa + 1);
1366 fc = le_to_host16(hdr->frame_control);
1367
1368 os_memset(&event, 0, sizeof(event));
1369 event.tx_status.type = WLAN_FC_GET_TYPE(fc);
1370 event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
1371 event.tx_status.dst = sa->dst_addr;
1372 event.tx_status.data = (const u8 *) hdr;
1373 event.tx_status.data_len = data_len - sizeof(*sa);
1374 event.tx_status.ack = sa->ack;
1375 wpa_supplicant_event(drv->hapd, EVENT_TX_STATUS, &event);
1376}
1377
1378
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001379/*
1380* Handle size of data problem. WEXT only allows data of 256 bytes for custom
1381* events, and p2p data can be much bigger. So the athr driver sends a small
1382* event telling me to collect the big data with an ioctl.
1383* On the first event, send all pending events to supplicant.
1384*/
1385static void fetch_pending_big_events(struct atheros_driver_data *drv)
1386{
1387 union wpa_event_data event;
1388 const struct ieee80211_mgmt *mgmt;
1389 u8 tbuf[IW_PRIV_SIZE_MASK]; /* max size is 2047 bytes */
1390 u16 fc, stype;
1391 struct iwreq iwr;
1392 size_t data_len;
1393 u32 freq, frame_type;
1394
1395 while (1) {
1396 os_memset(&iwr, 0, sizeof(iwr));
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -07001397 os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001398
1399 iwr.u.data.pointer = (void *) tbuf;
1400 iwr.u.data.length = sizeof(tbuf);
1401 iwr.u.data.flags = IEEE80211_IOC_P2P_FETCH_FRAME;
1402
1403 if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr)
1404 < 0) {
1405 if (errno == ENOSPC) {
1406 wpa_printf(MSG_DEBUG, "%s:%d exit",
1407 __func__, __LINE__);
1408 return;
1409 }
1410 wpa_printf(MSG_DEBUG, "athr: %s: P2P_BIG_PARAM["
1411 "P2P_FETCH_FRAME] failed: %s",
1412 __func__, strerror(errno));
1413 return;
1414 }
1415 data_len = iwr.u.data.length;
1416 wpa_hexdump(MSG_DEBUG, "athr: P2P_FETCH_FRAME data",
1417 (u8 *) tbuf, data_len);
1418 if (data_len < sizeof(freq) + sizeof(frame_type) + 24) {
1419 wpa_printf(MSG_DEBUG, "athr: frame too short");
1420 continue;
1421 }
1422 os_memcpy(&freq, tbuf, sizeof(freq));
1423 os_memcpy(&frame_type, &tbuf[sizeof(freq)],
1424 sizeof(frame_type));
1425 mgmt = (void *) &tbuf[sizeof(freq) + sizeof(frame_type)];
1426 data_len -= sizeof(freq) + sizeof(frame_type);
1427
1428 if (frame_type == IEEE80211_EV_RX_MGMT) {
1429 fc = le_to_host16(mgmt->frame_control);
1430 stype = WLAN_FC_GET_STYPE(fc);
1431
1432 wpa_printf(MSG_DEBUG, "athr: EV_RX_MGMT stype=%u "
1433 "freq=%u len=%u", stype, freq, (int) data_len);
1434
1435 if (stype == WLAN_FC_STYPE_ACTION) {
1436 os_memset(&event, 0, sizeof(event));
1437 event.rx_mgmt.frame = (const u8 *) mgmt;
1438 event.rx_mgmt.frame_len = data_len;
1439 wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT,
1440 &event);
1441 continue;
1442 }
Roshan Pius3a1667e2018-07-03 15:17:14 -07001443 } else if (frame_type == IEEE80211_EV_P2P_SEND_ACTION_CB) {
1444 wpa_printf(MSG_DEBUG,
1445 "%s: ACTION_CB frame_type=%u len=%zu",
1446 __func__, frame_type, data_len);
1447 send_action_cb_event(drv, (void *) mgmt, data_len);
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001448 } else {
1449 wpa_printf(MSG_DEBUG, "athr: %s unknown type %d",
1450 __func__, frame_type);
1451 continue;
1452 }
1453 }
1454}
1455
1456static void
1457atheros_wireless_event_atheros_custom(struct atheros_driver_data *drv,
1458 int opcode, char *buf, int len)
1459{
1460 switch (opcode) {
Roshan Pius3a1667e2018-07-03 15:17:14 -07001461 case IEEE80211_EV_P2P_SEND_ACTION_CB:
1462 wpa_printf(MSG_DEBUG, "WEXT: EV_P2P_SEND_ACTION_CB");
1463 fetch_pending_big_events(drv);
1464 break;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001465 case IEEE80211_EV_RX_MGMT:
1466 wpa_printf(MSG_DEBUG, "WEXT: EV_RX_MGMT");
1467 fetch_pending_big_events(drv);
1468 break;
1469 default:
1470 break;
1471 }
1472}
1473
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001474static void
1475atheros_wireless_event_wireless(struct atheros_driver_data *drv,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001476 char *data, unsigned int len)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001477{
1478 struct iw_event iwe_buf, *iwe = &iwe_buf;
1479 char *pos, *end, *custom, *buf;
1480
1481 pos = data;
1482 end = data + len;
1483
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001484 while ((size_t) (end - pos) >= IW_EV_LCP_LEN) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001485 /* Event data may be unaligned, so make a local, aligned copy
1486 * before processing. */
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001487 os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001488 wpa_printf(MSG_MSGDUMP, "Wireless event: cmd=0x%x len=%d",
1489 iwe->cmd, iwe->len);
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001490 if (iwe->len <= IW_EV_LCP_LEN || iwe->len > end - pos)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001491 return;
1492
1493 custom = pos + IW_EV_POINT_LEN;
1494 if (drv->we_version > 18 &&
1495 (iwe->cmd == IWEVMICHAELMICFAILURE ||
1496 iwe->cmd == IWEVASSOCREQIE ||
1497 iwe->cmd == IWEVCUSTOM)) {
1498 /* WE-19 removed the pointer from struct iw_point */
1499 char *dpos = (char *) &iwe_buf.u.data.length;
1500 int dlen = dpos - (char *) &iwe_buf;
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001501 os_memcpy(dpos, pos + IW_EV_LCP_LEN,
1502 sizeof(struct iw_event) - dlen);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001503 } else {
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001504 os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001505 custom += IW_EV_POINT_OFF;
1506 }
1507
1508 switch (iwe->cmd) {
1509 case IWEVEXPIRED:
1510 drv_event_disassoc(drv->hapd,
1511 (u8 *) iwe->u.addr.sa_data);
1512 break;
1513 case IWEVREGISTERED:
1514 atheros_new_sta(drv, (u8 *) iwe->u.addr.sa_data);
1515 break;
1516 case IWEVASSOCREQIE:
1517 /* Driver hack.. Use IWEVASSOCREQIE to bypass
1518 * IWEVCUSTOM size limitations. Need to handle this
1519 * just like IWEVCUSTOM.
1520 */
1521 case IWEVCUSTOM:
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001522 if (iwe->u.data.length > end - custom)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001523 return;
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001524 buf = os_malloc(iwe->u.data.length + 1);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001525 if (buf == NULL)
1526 return; /* XXX */
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001527 os_memcpy(buf, custom, iwe->u.data.length);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001528 buf[iwe->u.data.length] = '\0';
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07001529
1530 if (iwe->u.data.flags != 0) {
1531 atheros_wireless_event_atheros_custom(
1532 drv, (int) iwe->u.data.flags,
1533 buf, len);
1534 } else {
1535 atheros_wireless_event_wireless_custom(
1536 drv, buf, buf + iwe->u.data.length);
1537 }
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001538 os_free(buf);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001539 break;
1540 }
1541
1542 pos += iwe->len;
1543 }
1544}
1545
1546
1547static void
1548atheros_wireless_event_rtm_newlink(void *ctx,
1549 struct ifinfomsg *ifi, u8 *buf, size_t len)
1550{
1551 struct atheros_driver_data *drv = ctx;
1552 int attrlen, rta_len;
1553 struct rtattr *attr;
1554
1555 if (ifi->ifi_index != drv->ifindex)
1556 return;
1557
1558 attrlen = len;
1559 attr = (struct rtattr *) buf;
1560
1561 rta_len = RTA_ALIGN(sizeof(struct rtattr));
1562 while (RTA_OK(attr, attrlen)) {
1563 if (attr->rta_type == IFLA_WIRELESS) {
1564 atheros_wireless_event_wireless(
1565 drv, ((char *) attr) + rta_len,
1566 attr->rta_len - rta_len);
1567 }
1568 attr = RTA_NEXT(attr, attrlen);
1569 }
1570}
1571
1572
1573static int
1574atheros_get_we_version(struct atheros_driver_data *drv)
1575{
1576 struct iw_range *range;
1577 struct iwreq iwr;
1578 int minlen;
1579 size_t buflen;
1580
1581 drv->we_version = 0;
1582
1583 /*
1584 * Use larger buffer than struct iw_range in order to allow the
1585 * structure to grow in the future.
1586 */
1587 buflen = sizeof(struct iw_range) + 500;
1588 range = os_zalloc(buflen);
1589 if (range == NULL)
1590 return -1;
1591
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001592 os_memset(&iwr, 0, sizeof(iwr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001593 os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
1594 iwr.u.data.pointer = (caddr_t) range;
1595 iwr.u.data.length = buflen;
1596
1597 minlen = ((char *) &range->enc_capa) - (char *) range +
1598 sizeof(range->enc_capa);
1599
1600 if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001601 wpa_printf(MSG_ERROR, "ioctl[SIOCGIWRANGE]: %s",
1602 strerror(errno));
1603 os_free(range);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001604 return -1;
1605 } else if (iwr.u.data.length >= minlen &&
1606 range->we_version_compiled >= 18) {
1607 wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
1608 "WE(source)=%d enc_capa=0x%x",
1609 range->we_version_compiled,
1610 range->we_version_source,
1611 range->enc_capa);
1612 drv->we_version = range->we_version_compiled;
1613 }
1614
Jouni Malinen75ecf522011-06-27 15:19:46 -07001615 os_free(range);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001616 return 0;
1617}
1618
1619
1620static int
1621atheros_wireless_event_init(struct atheros_driver_data *drv)
1622{
1623 struct netlink_config *cfg;
1624
1625 atheros_get_we_version(drv);
1626
1627 cfg = os_zalloc(sizeof(*cfg));
1628 if (cfg == NULL)
1629 return -1;
1630 cfg->ctx = drv;
1631 cfg->newlink_cb = atheros_wireless_event_rtm_newlink;
1632 drv->netlink = netlink_init(cfg);
1633 if (drv->netlink == NULL) {
1634 os_free(cfg);
1635 return -1;
1636 }
1637
1638 return 0;
1639}
1640
1641
1642static int
1643atheros_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
1644 int encrypt, const u8 *own_addr, u32 flags)
1645{
1646 struct atheros_driver_data *drv = priv;
1647 unsigned char buf[3000];
1648 unsigned char *bp = buf;
1649 struct l2_ethhdr *eth;
1650 size_t len;
1651 int status;
1652
1653 /*
1654 * Prepend the Ethernet header. If the caller left us
1655 * space at the front we could just insert it but since
1656 * we don't know we copy to a local buffer. Given the frequency
1657 * and size of frames this probably doesn't matter.
1658 */
1659 len = data_len + sizeof(struct l2_ethhdr);
1660 if (len > sizeof(buf)) {
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001661 bp = os_malloc(len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001662 if (bp == NULL) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001663 wpa_printf(MSG_INFO,
1664 "EAPOL frame discarded, cannot malloc temp buffer of size %lu!",
1665 (unsigned long) len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001666 return -1;
1667 }
1668 }
1669 eth = (struct l2_ethhdr *) bp;
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001670 os_memcpy(eth->h_dest, addr, ETH_ALEN);
1671 os_memcpy(eth->h_source, own_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001672 eth->h_proto = host_to_be16(ETH_P_EAPOL);
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001673 os_memcpy(eth + 1, data, data_len);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001674
1675 wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len);
1676
1677 status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len);
1678
1679 if (bp != buf)
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001680 os_free(bp);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001681 return status;
1682}
1683
1684static void
1685handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
1686{
1687 struct atheros_driver_data *drv = ctx;
1688 drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr),
1689 len - sizeof(struct l2_ethhdr));
1690}
1691
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001692
1693static void atheros_read_fils_cap(struct atheros_driver_data *drv)
1694{
1695 int fils = 0;
1696
1697#ifdef CONFIG_FILS
1698 /* TODO: Would be better to have #ifdef on the IEEE80211_PARAM_* value
1699 * to automatically check this against the driver header files. */
1700 if (get80211param(drv, IEEE80211_PARAM_ENABLE_FILS, &fils) < 0) {
1701 wpa_printf(MSG_DEBUG,
1702 "%s: Failed to get FILS capability from driver",
1703 __func__);
1704 /* Assume driver does not support FILS */
1705 fils = 0;
1706 }
1707#endif /* CONFIG_FILS */
1708 drv->fils_en = fils;
1709 wpa_printf(MSG_DEBUG, "atheros: fils_en=%d", drv->fils_en);
1710}
1711
1712
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001713static void *
1714atheros_init(struct hostapd_data *hapd, struct wpa_init_params *params)
1715{
1716 struct atheros_driver_data *drv;
1717 struct ifreq ifr;
1718 struct iwreq iwr;
1719 char brname[IFNAMSIZ];
1720
1721 drv = os_zalloc(sizeof(struct atheros_driver_data));
1722 if (drv == NULL) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001723 wpa_printf(MSG_INFO,
1724 "Could not allocate memory for atheros driver data");
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001725 return NULL;
1726 }
1727
1728 drv->hapd = hapd;
1729 drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
1730 if (drv->ioctl_sock < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001731 wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
1732 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001733 goto bad;
1734 }
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001735 os_memcpy(drv->iface, params->ifname, sizeof(drv->iface));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001736
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001737 os_memset(&ifr, 0, sizeof(ifr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001738 os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
1739 if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001740 wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
1741 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001742 goto bad;
1743 }
1744 drv->ifindex = ifr.ifr_ifindex;
1745
1746 drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL,
1747 handle_read, drv, 1);
1748 if (drv->sock_xmit == NULL)
1749 goto bad;
1750 if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
1751 goto bad;
Dmitry Shmidtd5e49232012-12-03 15:08:10 -08001752 os_memcpy(drv->own_addr, params->own_addr, ETH_ALEN);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001753 if (params->bridge[0]) {
1754 wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.",
1755 params->bridge[0]);
1756 drv->sock_recv = l2_packet_init(params->bridge[0], NULL,
1757 ETH_P_EAPOL, handle_read, drv,
1758 1);
1759 if (drv->sock_recv == NULL)
1760 goto bad;
1761 } else if (linux_br_get(brname, drv->iface) == 0) {
1762 wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for "
1763 "EAPOL receive", brname);
1764 drv->sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL,
1765 handle_read, drv, 1);
1766 if (drv->sock_recv == NULL)
1767 goto bad;
1768 } else
1769 drv->sock_recv = drv->sock_xmit;
1770
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001771 os_memset(&iwr, 0, sizeof(iwr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001772 os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
1773
1774 iwr.u.mode = IW_MODE_MASTER;
1775
1776 if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001777 wpa_printf(MSG_ERROR,
1778 "Could not set interface to master mode! ioctl[SIOCSIWMODE]: %s",
1779 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001780 goto bad;
1781 }
1782
1783 /* mark down during setup */
1784 linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
1785 atheros_set_privacy(drv, 0); /* default to no privacy */
1786
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001787 if (atheros_receive_pkt(drv))
1788 goto bad;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001789
1790 if (atheros_wireless_event_init(drv))
1791 goto bad;
1792
Dmitry Shmidtd2986c22017-10-23 14:22:09 -07001793 /* Read FILS capability from the driver */
1794 atheros_read_fils_cap(drv);
1795
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001796 return drv;
1797bad:
Dmitry Shmidta54fa5f2013-01-15 13:53:35 -08001798 atheros_reset_appfilter(drv);
1799 if (drv->sock_raw)
1800 l2_packet_deinit(drv->sock_raw);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001801 if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
1802 l2_packet_deinit(drv->sock_recv);
1803 if (drv->sock_xmit != NULL)
1804 l2_packet_deinit(drv->sock_xmit);
1805 if (drv->ioctl_sock >= 0)
1806 close(drv->ioctl_sock);
Dmitry Shmidt41712582015-06-29 11:02:15 -07001807 os_free(drv);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001808 return NULL;
1809}
1810
1811
1812static void
1813atheros_deinit(void *priv)
1814{
1815 struct atheros_driver_data *drv = priv;
1816
Dmitry Shmidt04949592012-07-19 12:16:46 -07001817 atheros_reset_appfilter(drv);
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07001818
1819 if (drv->wpa_ie || drv->wps_beacon_ie || drv->wps_probe_resp_ie) {
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001820 atheros_set_opt_ie(priv, NULL, 0);
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07001821 wpabuf_free(drv->wpa_ie);
1822 wpabuf_free(drv->wps_beacon_ie);
1823 wpabuf_free(drv->wps_probe_resp_ie);
Dmitry Shmidtdda10c22015-03-24 16:05:01 -07001824 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001825 netlink_deinit(drv->netlink);
1826 (void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
1827 if (drv->ioctl_sock >= 0)
1828 close(drv->ioctl_sock);
1829 if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
1830 l2_packet_deinit(drv->sock_recv);
1831 if (drv->sock_xmit != NULL)
1832 l2_packet_deinit(drv->sock_xmit);
1833 if (drv->sock_raw)
1834 l2_packet_deinit(drv->sock_raw);
Dmitry Shmidt41712582015-06-29 11:02:15 -07001835 os_free(drv);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001836}
1837
1838static int
1839atheros_set_ssid(void *priv, const u8 *buf, int len)
1840{
1841 struct atheros_driver_data *drv = priv;
1842 struct iwreq iwr;
1843
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001844 os_memset(&iwr, 0, sizeof(iwr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001845 os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
1846 iwr.u.essid.flags = 1; /* SSID active */
1847 iwr.u.essid.pointer = (caddr_t) buf;
Roshan Pius3a1667e2018-07-03 15:17:14 -07001848 iwr.u.essid.length = len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001849
1850 if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001851 wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID,len=%d]: %s",
1852 len, strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001853 return -1;
1854 }
1855 return 0;
1856}
1857
1858static int
1859atheros_get_ssid(void *priv, u8 *buf, int len)
1860{
1861 struct atheros_driver_data *drv = priv;
1862 struct iwreq iwr;
1863 int ret = 0;
1864
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001865 os_memset(&iwr, 0, sizeof(iwr));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001866 os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
1867 iwr.u.essid.pointer = (caddr_t) buf;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001868 iwr.u.essid.length = (len > IW_ESSID_MAX_SIZE) ?
1869 IW_ESSID_MAX_SIZE : len;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001870
1871 if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
Dmitry Shmidt6c0da2b2015-01-05 13:08:17 -08001872 wpa_printf(MSG_ERROR, "ioctl[SIOCGIWESSID]: %s",
1873 strerror(errno));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001874 ret = -1;
1875 } else
1876 ret = iwr.u.essid.length;
1877
1878 return ret;
1879}
1880
1881static int
1882atheros_set_countermeasures(void *priv, int enabled)
1883{
1884 struct atheros_driver_data *drv = priv;
1885 wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
1886 return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled);
1887}
1888
1889static int
1890atheros_commit(void *priv)
1891{
1892 struct atheros_driver_data *drv = priv;
1893 return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);
1894}
1895
Jouni Malinen75ecf522011-06-27 15:19:46 -07001896static int atheros_set_authmode(void *priv, int auth_algs)
1897{
1898 int authmode;
1899
1900 if ((auth_algs & WPA_AUTH_ALG_OPEN) &&
1901 (auth_algs & WPA_AUTH_ALG_SHARED))
1902 authmode = IEEE80211_AUTH_AUTO;
1903 else if (auth_algs & WPA_AUTH_ALG_OPEN)
1904 authmode = IEEE80211_AUTH_OPEN;
1905 else if (auth_algs & WPA_AUTH_ALG_SHARED)
1906 authmode = IEEE80211_AUTH_SHARED;
1907 else
1908 return -1;
1909
1910 return set80211param(priv, IEEE80211_PARAM_AUTHMODE, authmode);
1911}
1912
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001913static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params)
1914{
1915 /*
1916 * TODO: Use this to replace set_authmode, set_privacy, set_ieee8021x,
1917 * set_generic_elem, and hapd_set_ssid.
1918 */
1919
1920 wpa_printf(MSG_DEBUG, "atheros: set_ap - pairwise_ciphers=0x%x "
1921 "group_cipher=0x%x key_mgmt_suites=0x%x auth_algs=0x%x "
1922 "wpa_version=0x%x privacy=%d interworking=%d",
1923 params->pairwise_ciphers, params->group_cipher,
1924 params->key_mgmt_suites, params->auth_algs,
1925 params->wpa_version, params->privacy, params->interworking);
1926 wpa_hexdump_ascii(MSG_DEBUG, "atheros: SSID",
1927 params->ssid, params->ssid_len);
1928 if (params->hessid)
1929 wpa_printf(MSG_DEBUG, "atheros: HESSID " MACSTR,
1930 MAC2STR(params->hessid));
1931 wpa_hexdump_buf(MSG_DEBUG, "atheros: beacon_ies",
1932 params->beacon_ies);
1933 wpa_hexdump_buf(MSG_DEBUG, "atheros: proberesp_ies",
1934 params->proberesp_ies);
1935 wpa_hexdump_buf(MSG_DEBUG, "atheros: assocresp_ies",
1936 params->assocresp_ies);
1937
Dmitry Shmidt203eadb2015-03-05 14:16:04 -08001938#if defined(CONFIG_HS20) && (defined(IEEE80211_PARAM_OSEN) || defined(CONFIG_ATHEROS_OSEN))
Dmitry Shmidt7d5c8f22014-03-03 13:53:28 -08001939 if (params->osen) {
1940 struct wpa_bss_params bss_params;
1941
1942 os_memset(&bss_params, 0, sizeof(struct wpa_bss_params));
1943 bss_params.enabled = 1;
1944 bss_params.wpa = 2;
1945 bss_params.wpa_pairwise = WPA_CIPHER_CCMP;
1946 bss_params.wpa_group = WPA_CIPHER_CCMP;
1947 bss_params.ieee802_1x = 1;
1948
1949 if (atheros_set_privacy(priv, 1) ||
1950 set80211param(priv, IEEE80211_PARAM_OSEN, 1))
1951 return -1;
1952
1953 return atheros_set_ieee8021x(priv, &bss_params);
1954 }
1955#endif /* CONFIG_HS20 && IEEE80211_PARAM_OSEN */
1956
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001957 return 0;
1958}
1959
Dmitry Shmidt04949592012-07-19 12:16:46 -07001960
Dmitry Shmidt04949592012-07-19 12:16:46 -07001961static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001962 int noack, unsigned int freq,
1963 const u16 *csa_offs, size_t csa_offs_len)
Dmitry Shmidt04949592012-07-19 12:16:46 -07001964{
1965 struct atheros_driver_data *drv = priv;
1966 u8 buf[1510];
1967 const struct ieee80211_mgmt *mgmt;
1968 struct ieee80211req_mgmtbuf *mgmt_frm;
1969
1970 mgmt = (const struct ieee80211_mgmt *) frm;
1971 wpa_printf(MSG_DEBUG, "%s frmlen = %lu " MACSTR, __func__,
1972 (unsigned long) data_len, MAC2STR(mgmt->da));
1973 mgmt_frm = (struct ieee80211req_mgmtbuf *) buf;
Dmitry Shmidt0e58d9b2015-12-22 10:59:44 -08001974 os_memcpy(mgmt_frm->macaddr, (u8 *)mgmt->da, IEEE80211_ADDR_LEN);
Dmitry Shmidt04949592012-07-19 12:16:46 -07001975 mgmt_frm->buflen = data_len;
1976 if (&mgmt_frm->buf[0] + data_len > buf + sizeof(buf)) {
1977 wpa_printf(MSG_INFO, "atheros: Too long frame for "
1978 "atheros_send_mgmt (%u)", (unsigned int) data_len);
1979 return -1;
1980 }
1981 os_memcpy(&mgmt_frm->buf[0], frm, data_len);
1982 return set80211priv(drv, IEEE80211_IOCTL_SEND_MGMT, mgmt_frm,
1983 sizeof(struct ieee80211req_mgmtbuf) + data_len);
1984}
1985
1986
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08001987#ifdef CONFIG_IEEE80211R
1988
Dmitry Shmidt04949592012-07-19 12:16:46 -07001989static int atheros_add_tspec(void *priv, const u8 *addr, u8 *tspec_ie,
1990 size_t tspec_ielen)
1991{
1992 struct atheros_driver_data *drv = priv;
1993 int retv;
1994 struct ieee80211req_res req;
1995 struct ieee80211req_res_addts *addts = &req.u.addts;
1996
1997 wpa_printf(MSG_DEBUG, "%s", __func__);
1998 req.type = IEEE80211_RESREQ_ADDTS;
1999 os_memcpy(&req.macaddr[0], addr, IEEE80211_ADDR_LEN);
2000 os_memcpy(addts->tspecie, tspec_ie, tspec_ielen);
2001 retv = set80211priv(drv, IEEE80211_IOCTL_RES_REQ, &req,
2002 sizeof(struct ieee80211req_res));
2003 if (retv < 0) {
2004 wpa_printf(MSG_DEBUG, "%s IEEE80211_IOCTL_RES_REQ FAILED "
2005 "retv = %d", __func__, retv);
2006 return -1;
2007 }
2008 os_memcpy(tspec_ie, addts->tspecie, tspec_ielen);
2009 return addts->status;
2010}
2011
2012
2013static int atheros_add_sta_node(void *priv, const u8 *addr, u16 auth_alg)
2014{
2015 struct atheros_driver_data *drv = priv;
2016 struct ieee80211req_res req;
2017 struct ieee80211req_res_addnode *addnode = &req.u.addnode;
2018
2019 wpa_printf(MSG_DEBUG, "%s", __func__);
2020 req.type = IEEE80211_RESREQ_ADDNODE;
2021 os_memcpy(&req.macaddr[0], addr, IEEE80211_ADDR_LEN);
2022 addnode->auth_alg = auth_alg;
2023 return set80211priv(drv, IEEE80211_IOCTL_RES_REQ, &req,
2024 sizeof(struct ieee80211req_res));
2025}
2026
2027#endif /* CONFIG_IEEE80211R */
2028
2029
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002030/* Use only to set a big param, get will not work. */
2031static int
2032set80211big(struct atheros_driver_data *drv, int op, const void *data, int len)
2033{
2034 struct iwreq iwr;
2035
2036 os_memset(&iwr, 0, sizeof(iwr));
2037 os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
2038
2039 iwr.u.data.pointer = (void *) data;
2040 iwr.u.data.length = len;
2041 iwr.u.data.flags = op;
2042 wpa_printf(MSG_DEBUG, "%s: op=0x%x=%d (%s) len=0x%x",
2043 __func__, op, op, athr_get_param_name(op), len);
2044
2045 if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_P2P_BIG_PARAM, &iwr) < 0) {
2046 wpa_printf(MSG_DEBUG, "%s: op=0x%x (%s) subop=0x%x=%d "
2047 "value=0x%x,0x%x failed: %d (%s)",
2048 __func__, op, athr_get_ioctl_name(op), iwr.u.mode,
2049 iwr.u.mode, iwr.u.data.length,
2050 iwr.u.data.flags, errno, strerror(errno));
2051 return -1;
2052 }
2053 return 0;
2054}
2055
2056
2057static int atheros_send_action(void *priv, unsigned int freq,
2058 unsigned int wait,
2059 const u8 *dst, const u8 *src,
2060 const u8 *bssid,
2061 const u8 *data, size_t data_len, int no_cck)
2062{
2063 struct atheros_driver_data *drv = priv;
2064 struct ieee80211_p2p_send_action *act;
2065 int res;
2066
2067 act = os_zalloc(sizeof(*act) + data_len);
2068 if (act == NULL)
2069 return -1;
2070 act->freq = freq;
2071 os_memcpy(act->dst_addr, dst, ETH_ALEN);
2072 os_memcpy(act->src_addr, src, ETH_ALEN);
2073 os_memcpy(act->bssid, bssid, ETH_ALEN);
2074 os_memcpy(act + 1, data, data_len);
2075 wpa_printf(MSG_DEBUG, "%s: freq=%d, wait=%u, dst=" MACSTR ", src="
2076 MACSTR ", bssid=" MACSTR,
2077 __func__, act->freq, wait, MAC2STR(act->dst_addr),
2078 MAC2STR(act->src_addr), MAC2STR(act->bssid));
2079 wpa_hexdump(MSG_MSGDUMP, "athr: act", (u8 *) act, sizeof(*act));
2080 wpa_hexdump(MSG_MSGDUMP, "athr: data", data, data_len);
2081
2082 res = set80211big(drv, IEEE80211_IOC_P2P_SEND_ACTION,
2083 act, sizeof(*act) + data_len);
2084 os_free(act);
2085 return res;
2086}
2087
2088
Dmitry Shmidt56052862013-10-04 10:23:25 -07002089#if defined(CONFIG_WNM) && defined(IEEE80211_APPIE_FRAME_WNM)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002090static int athr_wnm_tfs(struct atheros_driver_data *drv, const u8* peer,
2091 u8 *ie, u16 *len, enum wnm_oper oper)
2092{
2093#define IEEE80211_APPIE_MAX 1024 /* max appie buffer size */
2094 u8 buf[IEEE80211_APPIE_MAX];
2095 struct ieee80211req_getset_appiebuf *tfs_ie;
2096 u16 val;
2097
2098 wpa_printf(MSG_DEBUG, "atheros: ifname=%s, WNM TFS IE oper=%d " MACSTR,
2099 drv->iface, oper, MAC2STR(peer));
2100
2101 switch (oper) {
2102 case WNM_SLEEP_TFS_REQ_IE_SET:
2103 if (*len > IEEE80211_APPIE_MAX -
2104 sizeof(struct ieee80211req_getset_appiebuf)) {
2105 wpa_printf(MSG_DEBUG, "TFS Req IE(s) too large");
2106 return -1;
2107 }
2108 tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
2109 tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
2110 tfs_ie->app_buflen = ETH_ALEN + 2 + 2 + *len;
2111
2112 /* Command header for driver */
2113 os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
2114 val = oper;
2115 os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
2116 val = *len;
2117 os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
2118
2119 /* copy the ie */
2120 os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2 + 2, ie, *len);
2121
2122 if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie,
2123 IEEE80211_APPIE_MAX)) {
2124 wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: "
2125 "%s", __func__, strerror(errno));
2126 return -1;
2127 }
2128 break;
2129 case WNM_SLEEP_TFS_RESP_IE_ADD:
2130 tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
2131 tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
2132 tfs_ie->app_buflen = IEEE80211_APPIE_MAX -
2133 sizeof(struct ieee80211req_getset_appiebuf);
2134 /* Command header for driver */
2135 os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
2136 val = oper;
2137 os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
2138 val = 0;
2139 os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
2140
2141 if (set80211priv(drv, IEEE80211_IOCTL_GET_APPIEBUF, tfs_ie,
2142 IEEE80211_APPIE_MAX)) {
2143 wpa_printf(MSG_DEBUG, "%s: Failed to get WNM TFS IE: "
2144 "%s", __func__, strerror(errno));
2145 return -1;
2146 }
2147
2148 *len = tfs_ie->app_buflen;
2149 os_memcpy(ie, &(tfs_ie->app_buf[0]), *len);
2150 wpa_printf(MSG_DEBUG, "atheros: %c len=%d", tfs_ie->app_buf[0],
2151 *len);
2152 break;
2153 case WNM_SLEEP_TFS_RESP_IE_NONE:
2154 *len = 0;
2155 break;
2156 case WNM_SLEEP_TFS_IE_DEL:
2157 tfs_ie = (struct ieee80211req_getset_appiebuf *) buf;
2158 tfs_ie->app_frmtype = IEEE80211_APPIE_FRAME_WNM;
2159 tfs_ie->app_buflen = IEEE80211_APPIE_MAX -
2160 sizeof(struct ieee80211req_getset_appiebuf);
2161 /* Command header for driver */
2162 os_memcpy(&(tfs_ie->app_buf[0]), peer, ETH_ALEN);
2163 val = oper;
2164 os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN, &val, 2);
2165 val = 0;
2166 os_memcpy(&(tfs_ie->app_buf[0]) + ETH_ALEN + 2, &val, 2);
2167
2168 if (set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, tfs_ie,
2169 IEEE80211_APPIE_MAX)) {
2170 wpa_printf(MSG_DEBUG, "%s: Failed to set WNM TFS IE: "
2171 "%s", __func__, strerror(errno));
2172 return -1;
2173 }
2174 break;
2175 default:
2176 wpa_printf(MSG_DEBUG, "Unsupported TFS oper %d", oper);
2177 break;
2178 }
2179
2180 return 0;
2181}
2182
2183
2184static int atheros_wnm_sleep(struct atheros_driver_data *drv,
2185 const u8 *peer, enum wnm_oper oper)
2186{
2187 u8 *data, *pos;
2188 size_t dlen;
2189 int ret;
2190 u16 val;
2191
2192 wpa_printf(MSG_DEBUG, "atheros: WNM-Sleep Oper %d, " MACSTR,
2193 oper, MAC2STR(peer));
2194
2195 dlen = ETH_ALEN + 2 + 2;
2196 data = os_malloc(dlen);
2197 if (data == NULL)
2198 return -1;
2199
2200 /* Command header for driver */
2201 pos = data;
2202 os_memcpy(pos, peer, ETH_ALEN);
2203 pos += ETH_ALEN;
2204
2205 val = oper;
2206 os_memcpy(pos, &val, 2);
2207 pos += 2;
2208
2209 val = 0;
2210 os_memcpy(pos, &val, 2);
2211
2212 ret = atheros_set_wps_ie(drv, data, dlen, IEEE80211_APPIE_FRAME_WNM);
2213
2214 os_free(data);
2215
2216 return ret;
2217}
2218
2219
2220static int atheros_wnm_oper(void *priv, enum wnm_oper oper, const u8 *peer,
2221 u8 *buf, u16 *buf_len)
2222{
2223 struct atheros_driver_data *drv = priv;
2224
2225 switch (oper) {
2226 case WNM_SLEEP_ENTER_CONFIRM:
2227 case WNM_SLEEP_ENTER_FAIL:
2228 case WNM_SLEEP_EXIT_CONFIRM:
2229 case WNM_SLEEP_EXIT_FAIL:
2230 return atheros_wnm_sleep(drv, peer, oper);
2231 case WNM_SLEEP_TFS_REQ_IE_SET:
2232 case WNM_SLEEP_TFS_RESP_IE_ADD:
2233 case WNM_SLEEP_TFS_RESP_IE_NONE:
2234 case WNM_SLEEP_TFS_IE_DEL:
2235 return athr_wnm_tfs(drv, peer, buf, buf_len, oper);
2236 default:
2237 wpa_printf(MSG_DEBUG, "atheros: Unsupported WNM operation %d",
2238 oper);
2239 return -1;
2240 }
2241}
Dmitry Shmidt56052862013-10-04 10:23:25 -07002242#endif /* CONFIG_WNM && IEEE80211_APPIE_FRAME_WNM */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002243
2244
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002245const struct wpa_driver_ops wpa_driver_atheros_ops = {
2246 .name = "atheros",
2247 .hapd_init = atheros_init,
2248 .hapd_deinit = atheros_deinit,
2249 .set_ieee8021x = atheros_set_ieee8021x,
2250 .set_privacy = atheros_set_privacy,
2251 .set_key = atheros_set_key,
2252 .get_seqnum = atheros_get_seqnum,
2253 .flush = atheros_flush,
2254 .set_generic_elem = atheros_set_opt_ie,
2255 .sta_set_flags = atheros_sta_set_flags,
2256 .read_sta_data = atheros_read_sta_driver_data,
2257 .hapd_send_eapol = atheros_send_eapol,
2258 .sta_disassoc = atheros_sta_disassoc,
2259 .sta_deauth = atheros_sta_deauth,
2260 .hapd_set_ssid = atheros_set_ssid,
2261 .hapd_get_ssid = atheros_get_ssid,
2262 .set_countermeasures = atheros_set_countermeasures,
2263 .sta_clear_stats = atheros_sta_clear_stats,
2264 .commit = atheros_commit,
2265 .set_ap_wps_ie = atheros_set_ap_wps_ie,
Jouni Malinen75ecf522011-06-27 15:19:46 -07002266 .set_authmode = atheros_set_authmode,
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002267 .set_ap = atheros_set_ap,
Dmitry Shmidt04949592012-07-19 12:16:46 -07002268 .sta_assoc = atheros_sta_assoc,
2269 .sta_auth = atheros_sta_auth,
2270 .send_mlme = atheros_send_mgmt,
Dmitry Shmidtd80a4012015-11-05 16:35:40 -08002271#ifdef CONFIG_IEEE80211R
Dmitry Shmidt04949592012-07-19 12:16:46 -07002272 .add_tspec = atheros_add_tspec,
2273 .add_sta_node = atheros_add_sta_node,
2274#endif /* CONFIG_IEEE80211R */
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002275 .send_action = atheros_send_action,
Dmitry Shmidt56052862013-10-04 10:23:25 -07002276#if defined(CONFIG_WNM) && defined(IEEE80211_APPIE_FRAME_WNM)
Dmitry Shmidt61d9df32012-08-29 16:22:06 -07002277 .wnm_oper = atheros_wnm_oper,
Dmitry Shmidt56052862013-10-04 10:23:25 -07002278#endif /* CONFIG_WNM && IEEE80211_APPIE_FRAME_WNM */
Dmitry Shmidt051af732013-10-22 13:52:46 -07002279 .set_qos_map = atheros_set_qos_map,
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002280};