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