18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Driver interaction with Linux nl80211/cfg80211
3807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2003-2004, Instant802 Networks, Inc.
58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2005-2006, Devicescape Software, Inc.
68d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2009-2010, Atheros Communications
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
9c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
10c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <sys/types.h>
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <fcntl.h>
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <net/if.h>
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <netlink/genl/genl.h>
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <netlink/genl/ctrl.h>
19661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt#ifdef CONFIG_LIBNL3_ROUTE
20661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt#include <netlink/route/neighbour.h>
21661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt#endif /* CONFIG_LIBNL3_ROUTE */
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <linux/rtnetlink.h>
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <netpacket/packet.h>
241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include <linux/errqueue.h>
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eloop.h"
28cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt#include "common/qca-vendor.h"
297832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt#include "common/qca-vendor-attr.h"
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_defs.h"
311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "common/ieee802_11_common.h"
321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "l2_packet/l2_packet.h"
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "netlink.h"
346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "linux_defines.h"
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "linux_ioctl.h"
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "radiotap.h"
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "radiotap_iter.h"
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "rfkill.h"
396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#include "driver_nl80211.h"
401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifndef CONFIG_LIBNL20
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * libnl 1.1 has a bug, it tries to allocate socket numbers densely
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * but when you free a socket again it will mess up its bitmap and
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * and use the wrong number the next time it needs a socket ID.
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Therefore, we wrap the handle alloc/destroy and add our own pid
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * accounting.
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic uint32_t port_bitmap[32] = { 0 };
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct nl_handle *nl80211_handle_alloc(void *cb)
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_handle *handle;
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uint32_t pid = getpid() & 0x3FFFFF;
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	handle = nl_handle_alloc_cb(cb);
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < 1024; i++) {
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (port_bitmap[i / 32] & (1 << (i % 32)))
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		port_bitmap[i / 32] |= 1 << (i % 32);
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pid += i << 22;
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_socket_set_local_port(handle, pid);
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return handle;
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_handle_destroy(struct nl_handle *handle)
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uint32_t port = nl_socket_get_local_port(handle);
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	port >>= 22;
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	port_bitmap[port / 32] &= ~(1 << (port % 32));
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_handle_destroy(handle);
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_LIBNL20 */
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
855460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt#ifdef ANDROID
865460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt/* system/core/libnl_2 does not include nl_socket_set_nonblocking() */
875460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt#undef nl_socket_set_nonblocking
885460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt#define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h)
896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
905460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt#endif /* ANDROID */
915460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
925460547a121207cf7a99eac45e05fcdd83be3161Dmitry Shmidt
931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg)
941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_handle *handle;
961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	handle = nl80211_handle_alloc(cb);
981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (handle == NULL) {
991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
1001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "callbacks (%s)", dbg);
1011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
1021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
1031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (genl_connect(handle)) {
1051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
1061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "netlink (%s)", dbg);
1071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_handle_destroy(handle);
1081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
1091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
1101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return handle;
1121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
1131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nl_destroy_handles(struct nl_handle **handle)
1161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
1171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (*handle == NULL)
1181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
1191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_handle_destroy(*handle);
1201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	*handle = NULL;
1211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
1221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
12468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#if __WORDSIZE == 64
12568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#define ELOOP_SOCKET_INVALID	(intptr_t) 0x8888888888888889ULL
12668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#else
12768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#define ELOOP_SOCKET_INVALID	(intptr_t) 0x88888889ULL
12868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt#endif
12968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
13068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtstatic void nl80211_register_eloop_read(struct nl_handle **handle,
13168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt					eloop_sock_handler handler,
13268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt					void *eloop_data)
13368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt{
134807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt#ifdef CONFIG_LIBNL20
135807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	/*
136807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	 * libnl uses a pretty small buffer (32 kB that gets converted to 64 kB)
137807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	 * by default. It is possible to hit that limit in some cases where
138807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	 * operations are blocked, e.g., with a burst of Deauthentication frames
139807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	 * to hostapd and STA entry deletion. Try to increase the buffer to make
140807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	 * this less likely to occur.
141807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	 */
142807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	if (nl_socket_set_buffer_size(*handle, 262144, 0) < 0) {
143807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		wpa_printf(MSG_DEBUG,
144807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt			   "nl80211: Could not set nl_socket RX buffer size: %s",
145807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt			   strerror(errno));
146807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		/* continue anyway with the default (smaller) buffer */
147807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	}
148807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt#endif /* CONFIG_LIBNL20 */
149807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt
15068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	nl_socket_set_nonblocking(*handle);
15168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
15268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt				 eloop_data, *handle);
15368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	*handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID);
15468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt}
15568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
15668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
15768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidtstatic void nl80211_destroy_eloop_handle(struct nl_handle **handle)
15868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt{
15968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	*handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID);
16068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	eloop_unregister_read_sock(nl_socket_get_fd(*handle));
16168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	nl_destroy_handles(handle);
16268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt}
16368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
16468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
1651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nl80211_global_deinit(void *priv);
1667f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidtstatic void nl80211_check_global(struct nl80211_global *global);
1671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1684b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic void wpa_driver_nl80211_deinit(struct i802_bss *bss);
1699ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidtstatic int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
1709ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt					    struct hostapd_freq_params *freq);
171d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int
173e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidtwpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
1746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   const u8 *set_addr, int first,
1756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   const char *driver_params);
1761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_send_frame_cmd(struct i802_bss *bss,
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  unsigned int freq, unsigned int wait,
1781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				  const u8 *buf, size_t buf_len, u64 *cookie,
1791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				  int no_cck, int no_ack, int offchanok);
1804b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
1814b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					       int report);
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
186738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidt
1877832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidtstatic int nl80211_set_channel(struct i802_bss *bss,
1887832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt			       struct hostapd_freq_params *freq, int set_chan);
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     int ifindex, int disabled);
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
1936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			      int reset_mode);
1941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
195b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic int i802_set_iface_flags(struct i802_bss *bss, int up);
1966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_set_param(void *priv, const char *param);
19734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
19834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
19904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt/* Converts nl80211_chan_width to a common format */
2006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtenum chan_width convert2width(int width)
20104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt{
20204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	switch (width) {
20304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	case NL80211_CHAN_WIDTH_20_NOHT:
20404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return CHAN_WIDTH_20_NOHT;
20504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	case NL80211_CHAN_WIDTH_20:
20604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return CHAN_WIDTH_20;
20704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	case NL80211_CHAN_WIDTH_40:
20804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return CHAN_WIDTH_40;
20904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	case NL80211_CHAN_WIDTH_80:
21004f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return CHAN_WIDTH_80;
21104f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	case NL80211_CHAN_WIDTH_80P80:
21204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return CHAN_WIDTH_80P80;
21304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	case NL80211_CHAN_WIDTH_160:
21404f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		return CHAN_WIDTH_160;
21504f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	}
21604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	return CHAN_WIDTH_UNKNOWN;
21704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt}
21804f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
21904f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt
2206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint is_ap_interface(enum nl80211_iftype nlmode)
2211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
2227832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt	return nlmode == NL80211_IFTYPE_AP ||
2237832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt		nlmode == NL80211_IFTYPE_P2P_GO;
2241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
2251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint is_sta_interface(enum nl80211_iftype nlmode)
2281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
2297832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt	return nlmode == NL80211_IFTYPE_STATION ||
2307832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt		nlmode == NL80211_IFTYPE_P2P_CLIENT;
2311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
2321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
23434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int is_p2p_net_interface(enum nl80211_iftype nlmode)
2351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
2367832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt	return nlmode == NL80211_IFTYPE_P2P_CLIENT ||
2377832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt		nlmode == NL80211_IFTYPE_P2P_GO;
2381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstruct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv,
2426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  int ifindex)
2439ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt{
2449ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	struct i802_bss *bss;
2459ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt
2469ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	for (bss = drv->first_bss; bss; bss = bss->next) {
2479ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt		if (bss->ifindex == ifindex)
2489ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt			return bss;
2499ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	}
2509ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt
2519ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	return NULL;
2529ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt}
2539ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt
2549ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt
2556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int is_mesh_interface(enum nl80211_iftype nlmode)
2566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
2576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return nlmode == NL80211_IFTYPE_MESH_POINT;
2586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
2596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtvoid nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
2628bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt{
2638bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	if (drv->associated)
2648bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
2658bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	drv->associated = 0;
2668bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	os_memset(drv->bssid, 0, ETH_ALEN);
2678bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt}
2688bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
2698bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* nl80211 code */
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ack_handler(struct nl_msg *msg, void *arg)
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int *err = arg;
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*err = 0;
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_STOP;
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int finish_handler(struct nl_msg *msg, void *arg)
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int *ret = arg;
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*ret = 0;
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 void *arg)
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int *ret = arg;
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*ret = err->error;
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int no_seq_check(struct nl_msg *msg, void *arg)
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_OK;
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void nl80211_nlmsg_clear(struct nl_msg *msg)
3016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
3026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/*
3036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * Clear nlmsg data, e.g., to make sure key material is not left in
3046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * heap memory for unnecessarily long time.
3056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 */
3066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (msg) {
3076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		struct nlmsghdr *hdr = nlmsg_hdr(msg);
3086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		void *data = nlmsg_data(hdr);
3096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/*
3106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * This would use nlmsg_datalen() or the older nlmsg_len() if
3116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * only libnl were to maintain a stable API.. Neither will work
3126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * with all released versions, so just calculate the length
3136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * here.
3146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 */
3156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		int len = hdr->nlmsg_len - NLMSG_HDRLEN;
3166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		os_memset(data, 0, len);
3186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
3196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
3206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int send_and_recv(struct nl80211_global *global,
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 struct nl_handle *nl_handle, struct nl_msg *msg,
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 int (*valid_handler)(struct nl_msg *, void *),
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 void *valid_data)
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_cb *cb;
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int err = -ENOMEM;
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg)
3316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOMEM;
3326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	cb = nl_cb_clone(global->nl_cb);
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!cb)
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto out;
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	err = nl_send_auto_complete(nl_handle, msg);
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (err < 0)
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto out;
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	err = 1;
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (valid_handler)
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  valid_handler, valid_data);
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	while (err > 0) {
35268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		int res = nl_recvmsgs(nl_handle, cb);
353717574375e969e8272c6d1a26137286eac158abbDmitry Shmidt		if (res < 0) {
35468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			wpa_printf(MSG_INFO,
35568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt				   "nl80211: %s->nl_recvmsgs failed: %d",
35668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt				   __func__, res);
35768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		}
35868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	}
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt out:
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cb_put(cb);
3616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!valid_handler && valid_data == (void *) -1)
3626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl80211_nlmsg_clear(msg);
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return err;
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
3696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		       struct nl_msg *msg,
3706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		       int (*valid_handler)(struct nl_msg *, void *),
3716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		       void *valid_data)
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return send_and_recv(drv->global, drv->global->nl, msg,
3741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			     valid_handler, valid_data);
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct family_data {
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const char *group;
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int id;
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int family_handler(struct nl_msg *msg, void *arg)
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct family_data *res = arg;
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb[CTRL_ATTR_MAX + 1];
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *mcgrp;
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!tb[CTRL_ATTR_MCAST_GROUPS])
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  nla_len(mcgrp), NULL);
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       res->group,
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl_get_multicast_id(struct nl80211_global *global,
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       const char *family, const char *group)
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
4196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct family_data res = { group, -ENOENT };
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
4256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"),
4266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 0, 0, CTRL_CMD_GETFAMILY, 0) ||
4276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family)) {
4286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
4296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
4306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv(global, global->nl, msg, family_handler, &res);
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == 0)
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = res.id;
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtvoid * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
4406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   struct nl_msg *msg, int flags, uint8_t cmd)
4411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
4421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
4431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   0, flags, cmd, 0);
4441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
4451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
4486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
4496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss->wdev_id_set)
4506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return nla_put_u64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
4516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return nla_put_u32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
4526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
4536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstruct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd)
4566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
4576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
4586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nlmsg_alloc();
4606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg)
4616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NULL;
4626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!nl80211_cmd(bss->drv, msg, flags, cmd) ||
4646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nl80211_set_iface_id(msg, bss) < 0) {
4656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
4666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NULL;
4676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
4686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return msg;
4706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
4716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic struct nl_msg *
4746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtnl80211_ifindex_msg(struct wpa_driver_nl80211_data *drv, int ifindex,
4756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    int flags, uint8_t cmd)
4766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
4776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
4786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nlmsg_alloc();
4806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg)
4816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NULL;
4826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!nl80211_cmd(drv, msg, flags, cmd) ||
4846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex)) {
4856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
4866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NULL;
4876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
4886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return msg;
4906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
4916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstruct nl_msg * nl80211_drv_msg(struct wpa_driver_nl80211_data *drv, int flags,
4946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				uint8_t cmd)
4956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
4966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return nl80211_ifindex_msg(drv, drv->ifindex, flags, cmd);
4976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
4986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
4996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
5006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstruct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd)
5016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
5026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return nl80211_ifindex_msg(bss->drv, bss->ifindex, flags, cmd);
5036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
5046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
5056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
5061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstruct wiphy_idx_data {
5071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int wiphy_idx;
50834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	enum nl80211_iftype nlmode;
50934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 *macaddr;
5101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt};
5111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int netdev_info_handler(struct nl_msg *msg, void *arg)
5141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
5151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
5161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
5171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wiphy_idx_data *info = arg;
5181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
5201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
5211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (tb[NL80211_ATTR_WIPHY])
5231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
5241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
52534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (tb[NL80211_ATTR_IFTYPE])
52634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		info->nlmode = nla_get_u32(tb[NL80211_ATTR_IFTYPE]);
52734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
52834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (tb[NL80211_ATTR_MAC] && info->macaddr)
52934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		os_memcpy(info->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
53034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			  ETH_ALEN);
53134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
5321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return NL_SKIP;
5331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
5341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint nl80211_get_wiphy_index(struct i802_bss *bss)
5371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
5381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_msg *msg;
5391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wiphy_idx_data data = {
5401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		.wiphy_idx = -1,
54134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		.macaddr = NULL,
5421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	};
5431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
5456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
5461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
5481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return data.wiphy_idx;
5491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return -1;
5501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
5511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
55334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic enum nl80211_iftype nl80211_get_ifmode(struct i802_bss *bss)
55434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
55534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct nl_msg *msg;
55634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wiphy_idx_data data = {
55734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		.nlmode = NL80211_IFTYPE_UNSPECIFIED,
55834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		.macaddr = NULL,
55934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	};
56034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
5616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
5626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL80211_IFTYPE_UNSPECIFIED;
56334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
56434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
56534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return data.nlmode;
56634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return NL80211_IFTYPE_UNSPECIFIED;
56734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
56834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
56934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
57034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int nl80211_get_macaddr(struct i802_bss *bss)
57134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
57234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct nl_msg *msg;
57334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wiphy_idx_data data = {
57434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		.macaddr = bss->addr,
57534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	};
57634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
5776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
5786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
57934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
58034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data);
58134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
58234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
58334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
5841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
5851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				    struct nl80211_wiphy_data *w)
5861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
5871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_msg *msg;
5886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
5891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = nlmsg_alloc();
5911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!msg)
5921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
5931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
5946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS) ||
5956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx)) {
5966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
5976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
5986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
5991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL);
6011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ret) {
6021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
6031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "failed: ret=%d (%s)",
6041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   ret, strerror(-ret));
6051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
6061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return ret;
6071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
6081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
6111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
6121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl80211_wiphy_data *w = eloop_ctx;
61368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	int res;
6141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
615c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available");
6161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
61768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	res = nl_recvmsgs(handle, w->nl_cb);
618717574375e969e8272c6d1a26137286eac158abbDmitry Shmidt	if (res < 0) {
61968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
62068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			   __func__, res);
62168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	}
6221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
6231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int process_beacon_event(struct nl_msg *msg, void *arg)
6261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
6271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl80211_wiphy_data *w = arg;
6281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv;
6291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
6301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
6311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	union wpa_event_data event;
6321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
6341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
6351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (gnlh->cmd != NL80211_CMD_FRAME) {
6371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Unexpected beacon event? (%d)",
6381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   gnlh->cmd);
6391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NL_SKIP;
6401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
6411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!tb[NL80211_ATTR_FRAME])
6431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NL_SKIP;
6441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_for_each(drv, &w->drvs, struct wpa_driver_nl80211_data,
6461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 wiphy_list) {
6471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		os_memset(&event, 0, sizeof(event));
6481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		event.rx_mgmt.frame = nla_data(tb[NL80211_ATTR_FRAME]);
6491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		event.rx_mgmt.frame_len = nla_len(tb[NL80211_ATTR_FRAME]);
6501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
6511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
6521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return NL_SKIP;
6541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
6551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic struct nl80211_wiphy_data *
6581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtnl80211_get_wiphy_data_ap(struct i802_bss *bss)
6591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
6601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	static DEFINE_DL_LIST(nl80211_wiphys);
6611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl80211_wiphy_data *w;
6621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int wiphy_idx, found = 0;
6631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct i802_bss *tmp_bss;
6641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (bss->wiphy_data != NULL)
6661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return bss->wiphy_data;
6671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wiphy_idx = nl80211_get_wiphy_index(bss);
6691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_for_each(w, &nl80211_wiphys, struct nl80211_wiphy_data, list) {
6711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (w->wiphy_idx == wiphy_idx)
6721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			goto add;
6731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
6741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* alloc new one */
6761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	w = os_zalloc(sizeof(*w));
6771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (w == NULL)
6781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
6791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	w->wiphy_idx = wiphy_idx;
6801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_init(&w->bsss);
6811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_init(&w->drvs);
6821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
6841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!w->nl_cb) {
6851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		os_free(w);
6861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
6871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
6881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
6891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_beacon_event,
6901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  w);
6911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
6931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					 "wiphy beacons");
6941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (w->nl_beacons == NULL) {
6951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		os_free(w);
6961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
6971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
6981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211_register_beacons(bss->drv, w)) {
7001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl_destroy_handles(&w->nl_beacons);
7011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		os_free(w);
7021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
7031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
7041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
70568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	nl80211_register_eloop_read(&w->nl_beacons, nl80211_recv_beacons, w);
7061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_add(&nl80211_wiphys, &w->list);
7081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtadd:
7101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* drv entry for this bss already there? */
7111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
7121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (tmp_bss->drv == bss->drv) {
7131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			found = 1;
7141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
7151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
7161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
7171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* if not add it */
7181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!found)
7191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		dl_list_add(&w->drvs, &bss->drv->wiphy_list);
7201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_add(&w->bsss, &bss->wiphy_list);
7221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	bss->wiphy_data = w;
7231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return w;
7241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
7251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
7281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
7291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl80211_wiphy_data *w = bss->wiphy_data;
7301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct i802_bss *tmp_bss;
7311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int found = 0;
7321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (w == NULL)
7341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
7351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	bss->wiphy_data = NULL;
7361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_del(&bss->wiphy_list);
7371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* still any for this drv present? */
7391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
7401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (tmp_bss->drv == bss->drv) {
7411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			found = 1;
7421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
7431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
7441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
7451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* if not remove it */
7461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!found)
7471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		dl_list_del(&bss->drv->wiphy_list);
7481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!dl_list_empty(&w->bsss))
7501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
7511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
75268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	nl80211_destroy_eloop_handle(&w->nl_beacons);
7531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_cb_put(w->nl_cb);
7551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_del(&w->list);
7561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_free(w);
7571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
7581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!drv->associated)
7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(bssid, drv->bssid, ETH_ALEN);
7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!drv->associated)
7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(ssid, drv->ssid, drv->ssid_len);
7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return drv->ssid_len;
7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
782fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidtstatic void wpa_driver_nl80211_event_newlink(
7836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv, const char *ifname)
7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
787fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (os_strcmp(drv->first_bss->ifname, ifname) == 0) {
788fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if (if_nametoindex(drv->first_bss->ifname) == 0) {
789fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Interface %s does not exist - ignore RTM_NEWLINK",
790fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				   drv->first_bss->ifname);
791fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			return;
792fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		}
793fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if (!drv->if_removed)
794fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			return;
795fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Mark if_removed=0 for %s based on RTM_NEWLINK event",
796fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			   drv->first_bss->ifname);
797fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		drv->if_removed = 0;
798fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
799fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
801fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	os_strlcpy(event.interface_status.ifname, ifname,
802fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		   sizeof(event.interface_status.ifname));
803fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	event.interface_status.ievent = EVENT_INTERFACE_ADDED;
804fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
805fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt}
806fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
807fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
808fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidtstatic void wpa_driver_nl80211_event_dellink(
8096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv, const char *ifname)
810fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt{
811fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	union wpa_event_data event;
812fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
813fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (os_strcmp(drv->first_bss->ifname, ifname) == 0) {
814fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		if (drv->if_removed) {
815fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: if_removed already set - ignore RTM_DELLINK event for %s",
816fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				   ifname);
817fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			return;
81804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		}
819fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed - mark if_removed=1",
820fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			   ifname);
821fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		drv->if_removed = 1;
822fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	} else {
823fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		wpa_printf(MSG_DEBUG, "RTM_DELLINK: Interface '%s' removed",
824fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			   ifname);
8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
827fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
828fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	os_strlcpy(event.interface_status.ifname, ifname,
829fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		   sizeof(event.interface_status.ifname));
830fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 u8 *buf, size_t len)
8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int attrlen, rta_len;
8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rtattr *attr;
8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	attrlen = len;
8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	attr = (struct rtattr *) buf;
8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rta_len = RTA_ALIGN(sizeof(struct rtattr));
8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (RTA_OK(attr, attrlen)) {
8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (attr->rta_type == IFLA_IFNAME) {
847cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			if (os_strcmp(((char *) attr) + rta_len,
848cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				      drv->first_bss->ifname) == 0)
8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return 1;
8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else
8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		attr = RTA_NEXT(attr, attrlen);
8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  int ifindex, u8 *buf, size_t len)
8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->ifindex == ifindex)
8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 1;
8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
8677f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		nl80211_check_global(drv->global);
8688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "interface");
8706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL);
8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 1;
8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
8758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic struct wpa_driver_nl80211_data *
8791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtnl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len)
8801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
8811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv;
8821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_for_each(drv, &global->interfaces,
8831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 struct wpa_driver_nl80211_data, list) {
8841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (wpa_driver_nl80211_own_ifindex(drv, idx, buf, len) ||
8851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    have_ifidx(drv, idx))
8861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return drv;
8871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
8881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return NULL;
8891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
8901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
8938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 struct ifinfomsg *ifi,
8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 u8 *buf, size_t len)
8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl80211_global *global = ctx;
8971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv;
898fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	int attrlen;
8998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rtattr *attr;
9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 brid = 0;
9011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	char namebuf[IFNAMSIZ];
902fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	char ifname[IFNAMSIZ + 1];
903fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	char extra[100], *pos, *end;
9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
9061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!drv) {
907fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Ignore RTM_NEWLINK event for foreign ifindex %d",
908fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			   ifi->ifi_index);
9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
9108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
912fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	extra[0] = '\0';
913fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	pos = extra;
914fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	end = pos + sizeof(extra);
915fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	ifname[0] = '\0';
916fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
917fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	attrlen = len;
918fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	attr = (struct rtattr *) buf;
919fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	while (RTA_OK(attr, attrlen)) {
920fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		switch (attr->rta_type) {
921fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		case IFLA_IFNAME:
922fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			if (RTA_PAYLOAD(attr) >= IFNAMSIZ)
923fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				break;
924fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
925fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			ifname[RTA_PAYLOAD(attr)] = '\0';
926fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			break;
927fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		case IFLA_MASTER:
928fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			brid = nla_get_u32((struct nlattr *) attr);
929fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			pos += os_snprintf(pos, end - pos, " master=%u", brid);
930fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			break;
931fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		case IFLA_WIRELESS:
932fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			pos += os_snprintf(pos, end - pos, " wext");
933fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			break;
934fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		case IFLA_OPERSTATE:
935fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			pos += os_snprintf(pos, end - pos, " operstate=%u",
936fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt					   nla_get_u32((struct nlattr *) attr));
937fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			break;
938fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		case IFLA_LINKMODE:
939fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			pos += os_snprintf(pos, end - pos, " linkmode=%u",
940fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt					   nla_get_u32((struct nlattr *) attr));
941fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			break;
942fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		}
943fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		attr = RTA_NEXT(attr, attrlen);
944fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
945fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	extra[sizeof(extra) - 1] = '\0';
946fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
947661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	wpa_printf(MSG_DEBUG, "RTM_NEWLINK: ifi_index=%d ifname=%s%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
948661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		   ifi->ifi_index, ifname, extra, ifi->ifi_family,
949661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		   ifi->ifi_flags,
9508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
9518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
9528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
9538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
9548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
9567f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		namebuf[0] = '\0';
9571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (if_indextoname(ifi->ifi_index, namebuf) &&
9587f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		    linux_iface_up(drv->global->ioctl_sock, namebuf) > 0) {
9591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
9601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "event since interface %s is up", namebuf);
9616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			drv->ignore_if_down_event = 0;
9621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return;
9631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
9647f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Interface down (%s/%s)",
9657f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt			   namebuf, ifname);
9667f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		if (os_strcmp(drv->first_bss->ifname, ifname) != 0) {
9677f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt			wpa_printf(MSG_DEBUG,
9687f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt				   "nl80211: Not the main interface (%s) - do not indicate interface down",
9697f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt				   drv->first_bss->ifname);
9707f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		} else if (drv->ignore_if_down_event) {
9711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
9721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "event generated by mode change");
9731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			drv->ignore_if_down_event = 0;
9741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		} else {
9751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			drv->if_disabled = 1;
9761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_supplicant_event(drv->ctx,
9771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					     EVENT_INTERFACE_DISABLED, NULL);
978a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
979a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt			/*
980a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt			 * Try to get drv again, since it may be removed as
981a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt			 * part of the EVENT_INTERFACE_DISABLED handling for
982a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt			 * dynamic interfaces
983a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt			 */
984a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt			drv = nl80211_find_drv(global, ifi->ifi_index,
985a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt					       buf, len);
986a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt			if (!drv)
987a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt				return;
9881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
9921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (if_indextoname(ifi->ifi_index, namebuf) &&
9937f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		    linux_iface_up(drv->global->ioctl_sock, namebuf) == 0) {
9941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
9951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "event since interface %s is down",
9961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   namebuf);
997cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		} else if (if_nametoindex(drv->first_bss->ifname) == 0) {
99804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
99904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				   "event since interface %s does not exist",
1000cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				   drv->first_bss->ifname);
100104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		} else if (drv->if_removed) {
100204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
100304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				   "event since interface %s is marked "
1004cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				   "removed", drv->first_bss->ifname);
10051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		} else {
10069ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt			struct i802_bss *bss;
10079ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt			u8 addr[ETH_ALEN];
10089ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt
10099ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt			/* Re-read MAC address as it may have changed */
10109ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt			bss = get_bss_ifindex(drv, ifi->ifi_index);
10119ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt			if (bss &&
10129ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt			    linux_get_ifhwaddr(drv->global->ioctl_sock,
10139ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt					       bss->ifname, addr) < 0) {
10149ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt				wpa_printf(MSG_DEBUG,
10159ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt					   "nl80211: %s: failed to re-read MAC address",
10169ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt					   bss->ifname);
10179ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt			} else if (bss &&
10189ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt				   os_memcmp(addr, bss->addr, ETH_ALEN) != 0) {
10199ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt				wpa_printf(MSG_DEBUG,
10209ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt					   "nl80211: Own MAC address on ifindex %d (%s) changed from "
10219ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt					   MACSTR " to " MACSTR,
10229ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt					   ifi->ifi_index, bss->ifname,
10239ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt					   MAC2STR(bss->addr),
10249ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt					   MAC2STR(addr));
10259ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt				os_memcpy(bss->addr, addr, ETH_ALEN);
10269ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt			}
10279ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt
10281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Interface up");
10291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			drv->if_disabled = 0;
10301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
10311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					     NULL);
10321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Some drivers send the association event before the operup event--in
10378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * fails. This will hit us when wpa_supplicant does not need to do
10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * IEEE 802.1X authentication
10408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->operstate == 1 &&
10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
1043fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	    !(ifi->ifi_flags & IFF_RUNNING)) {
1044fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Set IF_OPER_UP again based on ifi_flags and expected operstate");
10451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
10468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       -1, IF_OPER_UP);
10478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1049fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ifname[0])
1050fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		wpa_driver_nl80211_event_newlink(drv, ifname);
1051fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
10528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ifi->ifi_family == AF_BRIDGE && brid) {
10536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		struct i802_bss *bss;
10546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* device has been added to bridge */
10566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (!if_indextoname(brid, namebuf)) {
10576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG,
10586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "nl80211: Could not find bridge ifname for ifindex %u",
10596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   brid);
10606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return;
10616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
10628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   brid, namebuf);
10648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		add_ifidx(drv, brid);
10656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
10666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		for (bss = drv->first_bss; bss; bss = bss->next) {
10676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (os_strcmp(ifname, bss->ifname) == 0) {
10686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				os_strlcpy(bss->brname, namebuf, IFNAMSIZ);
10696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				break;
10706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			}
10716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
10728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
10778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 struct ifinfomsg *ifi,
10788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 u8 *buf, size_t len)
10798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl80211_global *global = ctx;
10811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv;
1082fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	int attrlen;
10838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rtattr *attr;
10848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 brid = 0;
1085fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	char ifname[IFNAMSIZ + 1];
1086661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	char extra[100], *pos, *end;
10878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
10891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!drv) {
1090fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Ignore RTM_DELLINK event for foreign ifindex %d",
1091fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			   ifi->ifi_index);
10921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
10931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
10941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1095661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	extra[0] = '\0';
1096661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	pos = extra;
1097661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	end = pos + sizeof(extra);
1098fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	ifname[0] = '\0';
1099fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
11008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	attrlen = len;
11018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	attr = (struct rtattr *) buf;
11028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (RTA_OK(attr, attrlen)) {
1103fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		switch (attr->rta_type) {
1104fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		case IFLA_IFNAME:
1105fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			if (RTA_PAYLOAD(attr) >= IFNAMSIZ)
1106fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				break;
1107fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			os_memcpy(ifname, RTA_DATA(attr), RTA_PAYLOAD(attr));
1108fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			ifname[RTA_PAYLOAD(attr)] = '\0';
1109fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			break;
1110fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		case IFLA_MASTER:
11118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			brid = nla_get_u32((struct nlattr *) attr);
1112661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			pos += os_snprintf(pos, end - pos, " master=%u", brid);
1113661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			break;
1114661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		case IFLA_OPERSTATE:
1115661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			pos += os_snprintf(pos, end - pos, " operstate=%u",
1116661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt					   nla_get_u32((struct nlattr *) attr));
1117661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			break;
1118661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		case IFLA_LINKMODE:
1119661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			pos += os_snprintf(pos, end - pos, " linkmode=%u",
1120661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt					   nla_get_u32((struct nlattr *) attr));
1121fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			break;
1122fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		}
11238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		attr = RTA_NEXT(attr, attrlen);
11248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1125661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	extra[sizeof(extra) - 1] = '\0';
11268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1127661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	wpa_printf(MSG_DEBUG, "RTM_DELLINK: ifi_index=%d ifname=%s%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
1128661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		   ifi->ifi_index, ifname, extra, ifi->ifi_family,
1129661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		   ifi->ifi_flags,
1130661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		   (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
1131661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		   (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
1132661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
1133661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
1134661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
1135661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	if (ifname[0] && (ifi->ifi_family != AF_BRIDGE || !brid))
1136fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		wpa_driver_nl80211_event_dellink(drv, ifname);
1137fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
11388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ifi->ifi_family == AF_BRIDGE && brid) {
11398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* device has been removed from bridge */
11408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		char namebuf[IFNAMSIZ];
11418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (!if_indextoname(brid, namebuf)) {
11436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG,
11446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "nl80211: Could not find bridge ifname for ifindex %u",
11456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   brid);
11466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		} else {
11476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG,
11486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "nl80211: Remove ifindex %u for bridge %s",
11496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   brid, namebuf);
11506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
11516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		del_ifidx(drv, brid);
11528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtunsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
115787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen{
115887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	struct nl_msg *msg;
115987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	int ret;
116087fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	struct nl80211_bss_info_arg arg;
116187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
11626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
116387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	os_memset(&arg, 0, sizeof(arg));
116487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	arg.drv = drv;
116587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
116687fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	if (ret == 0) {
11676dc03bd757d3befd2c03a543a402338db03914d6Dmitry Shmidt		unsigned int freq = drv->nlmode == NL80211_IFTYPE_ADHOC ?
11686dc03bd757d3befd2c03a543a402338db03914d6Dmitry Shmidt			arg.ibss_freq : arg.assoc_freq;
116987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		wpa_printf(MSG_DEBUG, "nl80211: Operating frequency for the "
11706dc03bd757d3befd2c03a543a402338db03914d6Dmitry Shmidt			   "associated BSS from scan results: %u MHz", freq);
11716dc03bd757d3befd2c03a543a402338db03914d6Dmitry Shmidt		if (freq)
11726dc03bd757d3befd2c03a543a402338db03914d6Dmitry Shmidt			drv->assoc_freq = freq;
1173b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return drv->assoc_freq;
117487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	}
117587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
117687fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		   "(%s)", ret, strerror(-ret));
117787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	return drv->assoc_freq;
117887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen}
117987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
118087fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
11816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int get_link_signal(struct nl_msg *msg, void *arg)
11828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
11846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
11856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
11866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
11876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
11886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 },
1189f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		[NL80211_STA_INFO_BEACON_SIGNAL_AVG] = { .type = NLA_U8 },
11906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	};
11916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
11926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
11936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
11946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
11956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
11966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
11976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	};
11986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_signal_info *sig_change = arg;
1199661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
12006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
12016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
12026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!tb[NL80211_ATTR_STA_INFO] ||
12036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
12046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			     tb[NL80211_ATTR_STA_INFO], policy))
12056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
12066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!sinfo[NL80211_STA_INFO_SIGNAL])
12076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
12088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	sig_change->current_signal =
12106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		(s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
12118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (sinfo[NL80211_STA_INFO_SIGNAL_AVG])
12136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		sig_change->avg_signal =
12146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			(s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG]);
12156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	else
12166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		sig_change->avg_signal = 0;
12178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1218f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt	if (sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG])
1219f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		sig_change->avg_beacon_signal =
1220f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt			(s8)
1221f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt			nla_get_u8(sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG]);
1222f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt	else
1223f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt		sig_change->avg_beacon_signal = 0;
1224f73259cc00af557e36add405799b7f2326587c13Dmitry Shmidt
12256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
12266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
12276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				     sinfo[NL80211_STA_INFO_TX_BITRATE],
12286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				     rate_policy)) {
12296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			sig_change->current_txrate = 0;
12306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		} else {
12316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (rinfo[NL80211_RATE_INFO_BITRATE]) {
12326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				sig_change->current_txrate =
12336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					nla_get_u16(rinfo[
12346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					     NL80211_RATE_INFO_BITRATE]) * 100;
12356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			}
12366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
12378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return NL_SKIP;
12408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
12446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    struct wpa_signal_info *sig)
12458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
12478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	sig->current_signal = -9999;
12496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	sig->current_txrate = 0;
12508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_STATION)) ||
12526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid)) {
12536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
12546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
12558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return send_and_recv_msgs(drv, msg, get_link_signal, sig);
12588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int get_link_noise(struct nl_msg *msg, void *arg)
12621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
12636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
12646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
12656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
12666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
12676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
12686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
12696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	};
12706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_signal_info *sig_change = arg;
12711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
12726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
12736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
12746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
12756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!tb[NL80211_ATTR_SURVEY_INFO]) {
12766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: survey data missing!");
12776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
12781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
12791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
12806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
12816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			     tb[NL80211_ATTR_SURVEY_INFO],
12826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			     survey_policy)) {
12836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: failed to parse nested "
12846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "attributes!");
12856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
1286d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	}
1287d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
12886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
12896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
129004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
12916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
12926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    sig_change->frequency)
12936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
129404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
12956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!sinfo[NL80211_SURVEY_INFO_NOISE])
12966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
12979767226d8e6a1adaa33beb9f517ef40dddfa460cDmitry Shmidt
12986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	sig_change->current_noise =
12996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		(s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
13009767226d8e6a1adaa33beb9f517ef40dddfa460cDmitry Shmidt
13016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return NL_SKIP;
13029767226d8e6a1adaa33beb9f517ef40dddfa460cDmitry Shmidt}
13039767226d8e6a1adaa33beb9f517ef40dddfa460cDmitry Shmidt
13049767226d8e6a1adaa33beb9f517ef40dddfa460cDmitry Shmidt
13056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
13066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   struct wpa_signal_info *sig_change)
130704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
13086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
130904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
13106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	sig_change->current_noise = 9999;
13116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	sig_change->frequency = drv->assoc_freq;
1312e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
13136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
13146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return send_and_recv_msgs(drv, msg, get_link_noise, sig_change);
13151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
13161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
13171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
13186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
13196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					     void *handle)
13208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_cb *cb = eloop_ctx;
13226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int res;
13238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_MSGDUMP, "nl80211: Event message available");
13258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	res = nl_recvmsgs(handle, cb);
13276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (res < 0) {
13286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
13296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   __func__, res);
13306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
13318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/**
13356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain
13366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @priv: driver_nl80211 private data
13376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @alpha2_arg: country to which to switch to
13386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Returns: 0 on success, -1 on failure
13396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt *
13406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * This asks nl80211 to set the regulatory domain for given
13416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * country ISO / IEC alpha2.
13426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */
13436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
13448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
13469866086a955d00e237cc8df3722e7dff75c02532Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
13476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	char alpha2[3];
13486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
13498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nlmsg_alloc();
13516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg)
13526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOMEM;
13538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	alpha2[0] = alpha2_arg[0];
13556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	alpha2[1] = alpha2_arg[1];
13566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	alpha2[2] = '\0';
135704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
13586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG) ||
13596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, alpha2)) {
13606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
13616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -EINVAL;
13628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (send_and_recv_msgs(drv, msg, NULL, NULL))
13646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -EINVAL;
13656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 0;
13668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_get_country(struct nl_msg *msg, void *arg)
13708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	char *alpha2 = arg;
13726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
13736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
13741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
13756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
13766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
13776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!tb_msg[NL80211_ATTR_REG_ALPHA2]) {
13786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: No country information available");
13796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
13801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
13816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_strlcpy(alpha2, nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]), 3);
13826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return NL_SKIP;
13838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_nl80211_get_country(void *priv, char *alpha2)
13878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
13896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
13906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
13916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
13928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nlmsg_alloc();
13946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg)
13956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOMEM;
13968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
13986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	alpha2[0] = '\0';
13996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, nl80211_get_country, alpha2);
14006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!alpha2[0])
14016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
14028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
14048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
14088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
1410d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
14116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
14126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (global->nl_cb == NULL) {
14136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
14146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "callbacks");
14156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
14166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
14178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	global->nl = nl_create_handle(global->nl_cb, "nl");
14196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (global->nl == NULL)
14206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto err;
14218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");
14236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (global->nl80211_id < 0) {
14246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
14256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "found");
14266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto err;
14278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	global->nl_event = nl_create_handle(global->nl_cb, "event");
14306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (global->nl_event == NULL)
14316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto err;
14328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = nl_get_multicast_id(global, "nl80211", "scan");
14346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret >= 0)
14356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = nl_socket_add_membership(global->nl_event, ret);
14366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret < 0) {
14376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
14386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "membership for scan events: %d (%s)",
14396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   ret, strerror(-ret));
14406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto err;
14418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = nl_get_multicast_id(global, "nl80211", "mlme");
14446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret >= 0)
14456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = nl_socket_add_membership(global->nl_event, ret);
14466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret < 0) {
14476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
14486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "membership for mlme events: %d (%s)",
14496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   ret, strerror(-ret));
14506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto err;
14518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = nl_get_multicast_id(global, "nl80211", "regulatory");
14546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret >= 0)
14556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = nl_socket_add_membership(global->nl_event, ret);
14566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret < 0) {
14576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
14586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "membership for regulatory events: %d (%s)",
14596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   ret, strerror(-ret));
14606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/* Continue without regulatory events */
14618da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	}
14628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = nl_get_multicast_id(global, "nl80211", "vendor");
14646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret >= 0)
14656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = nl_socket_add_membership(global->nl_event, ret);
14666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret < 0) {
14676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
14686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "membership for vendor events: %d (%s)",
14696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   ret, strerror(-ret));
14706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/* Continue without vendor events */
14718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
14736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
14746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		  no_seq_check, NULL);
14756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
14766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		  process_global_event, global);
14776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
14786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl80211_register_eloop_read(&global->nl_event,
14796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    wpa_driver_nl80211_event_receive,
14806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    global->nl_cb);
14816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
14826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 0;
14836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
14846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidterr:
14856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl_destroy_handles(&global->nl_event);
14866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl_destroy_handles(&global->nl);
14876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl_cb_put(global->nl_cb);
14886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	global->nl_cb = NULL;
14896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return -1;
14908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14937f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidtstatic void nl80211_check_global(struct nl80211_global *global)
14947f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt{
14957f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	struct nl_handle *handle;
14967f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	const char *groups[] = { "scan", "mlme", "regulatory", "vendor", NULL };
14977f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	int ret;
14987f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	unsigned int i;
14997f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
15007f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	/*
15017f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	 * Try to re-add memberships to handle case of cfg80211 getting reloaded
15027f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	 * and all registration having been cleared.
15037f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	 */
15047f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	handle = (void *) (((intptr_t) global->nl_event) ^
15057f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt			   ELOOP_SOCKET_INVALID);
15067f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
15077f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	for (i = 0; groups[i]; i++) {
15087f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		ret = nl_get_multicast_id(global, "nl80211", groups[i]);
15097f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		if (ret >= 0)
15107f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt			ret = nl_socket_add_membership(handle, ret);
15117f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		if (ret < 0) {
15127f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt			wpa_printf(MSG_INFO,
15137f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt				   "nl80211: Could not re-add multicast membership for %s events: %d (%s)",
15147f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt				   groups[i], ret, strerror(-ret));
15157f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		}
15167f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	}
15177f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt}
15187f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
15197f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
15206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void wpa_driver_nl80211_rfkill_blocked(void *ctx)
15218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
15236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/*
15246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * This may be for any interface; use ifdown event to disable
15256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * interface.
15266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 */
15276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
15288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
15316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
15326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = ctx;
15336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
15346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (i802_set_iface_flags(drv->first_bss, 1)) {
15356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
15366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "after rfkill unblock");
15376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return;
15388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
15396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* rtnetlink ifup handler will report interface as enabled */
15408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
15418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
15446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt						      void *eloop_ctx,
15456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt						      void *handle)
15468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = eloop_ctx;
15486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	u8 data[2048];
15496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct msghdr msg;
15506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct iovec entry;
15516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	u8 control[512];
15526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct cmsghdr *cmsg;
15536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int res, found_ee = 0, found_wifi = 0, acked = 0;
15546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	union wpa_event_data event;
15556dc03bd757d3befd2c03a543a402338db03914d6Dmitry Shmidt
15566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	memset(&msg, 0, sizeof(msg));
15576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg.msg_iov = &entry;
15586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg.msg_iovlen = 1;
15596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	entry.iov_base = data;
15606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	entry.iov_len = sizeof(data);
15616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg.msg_control = &control;
15626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg.msg_controllen = sizeof(control);
1563c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
15646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	res = recvmsg(sock, &msg, MSG_ERRQUEUE);
15656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* if error or not fitting 802.3 header, return */
15666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (res < 14)
15676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return;
15688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
15706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	{
15716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (cmsg->cmsg_level == SOL_SOCKET &&
15726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    cmsg->cmsg_type == SCM_WIFI_STATUS) {
15736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			int *ack;
15746dc03bd757d3befd2c03a543a402338db03914d6Dmitry Shmidt
15756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			found_wifi = 1;
15766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			ack = (void *)CMSG_DATA(cmsg);
15776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			acked = *ack;
15786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
15798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (cmsg->cmsg_level == SOL_PACKET &&
15816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    cmsg->cmsg_type == PACKET_TX_TIMESTAMP) {
15826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			struct sock_extended_err *err =
15836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				(struct sock_extended_err *)CMSG_DATA(cmsg);
15848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (err->ee_origin == SO_EE_ORIGIN_TXSTATUS)
15866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				found_ee = 1;
15876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
15886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
15898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!found_ee || !found_wifi)
15916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return;
15928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	memset(&event, 0, sizeof(event));
15946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	event.eapol_tx_status.dst = data;
15956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	event.eapol_tx_status.data = data + 14;
15966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	event.eapol_tx_status.data_len = res - 14;
15976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	event.eapol_tx_status.ack = acked;
15986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
15996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
16008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_init_bss(struct i802_bss *bss)
16036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
16046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
16056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!bss->nl_cb)
16066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
16078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
16096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		  no_seq_check, NULL);
16106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
16116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		  process_bss_event, bss);
16128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 0;
16146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
16158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void nl80211_destroy_bss(struct i802_bss *bss)
16186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
16196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl_cb_put(bss->nl_cb);
16206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	bss->nl_cb = NULL;
16218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
16228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
16256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  void *global_priv, int hostapd,
16266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  const u8 *set_addr,
16276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  const char *driver_params)
1628700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt{
16296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv;
16306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct rfkill_config *rcfg;
16316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss;
1632700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
16336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (global_priv == NULL)
16346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NULL;
16356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv = os_zalloc(sizeof(*drv));
16366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv == NULL)
16376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NULL;
16386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->global = global_priv;
16396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->ctx = ctx;
16406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->hostapd = !!hostapd;
16416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->eapol_sock = -1;
1642ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
1643ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	/*
1644ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	 * There is no driver capability flag for this, so assume it is
1645ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	 * supported and disable this on first attempt to use if the driver
1646ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	 * rejects the command due to missing support.
1647ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	 */
1648ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	drv->set_rekey_offload = 1;
1649ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
16506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
16516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->if_indices = drv->default_if_indices;
1652700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
16536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->first_bss = os_zalloc(sizeof(*drv->first_bss));
16546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!drv->first_bss) {
16556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		os_free(drv);
16566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NULL;
1657700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	}
16586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	bss = drv->first_bss;
16596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	bss->drv = drv;
16606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	bss->ctx = ctx;
16616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
16626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
16636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->monitor_ifidx = -1;
16646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->monitor_sock = -1;
16656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->eapol_tx_sock = -1;
16666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
16676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
16686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_init_bss(bss))
16696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto failed;
1670700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
16716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	rcfg = os_zalloc(sizeof(*rcfg));
16726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (rcfg == NULL)
16736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto failed;
16746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	rcfg->ctx = drv;
16756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname));
16766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked;
16776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked;
16786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->rfkill = rfkill_init(rcfg);
16796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->rfkill == NULL) {
16806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available");
16816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		os_free(rcfg);
1682700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	}
1683700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
16846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (linux_iface_up(drv->global->ioctl_sock, ifname) > 0)
16856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		drv->start_iface_up = 1;
1686700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
16876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1, driver_params))
16886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto failed;
1689700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
16906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
16916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->eapol_tx_sock < 0)
16926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto failed;
1693700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
16946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->data_tx_status) {
16956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		int enabled = 1;
1696700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
16976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
16986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			       &enabled, sizeof(enabled)) < 0) {
16996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG,
17006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				"nl80211: wifi status sockopt failed\n");
17016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			drv->data_tx_status = 0;
17026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (!drv->use_monitor)
17036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				drv->capa.flags &=
17046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
17056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		} else {
17066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			eloop_register_read_sock(drv->eapol_tx_sock,
17076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				wpa_driver_nl80211_handle_eapol_tx_status,
17086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				drv, NULL);
17096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
17101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
17111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
17126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->global) {
17137f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		nl80211_check_global(drv->global);
17146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		dl_list_add(&drv->global->interfaces, &drv->list);
17156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		drv->in_interface_list = 1;
17168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1717fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
17186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return bss;
1719fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
17206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfailed:
17216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_driver_nl80211_deinit(bss);
17226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return NULL;
17238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
17248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/**
17276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * wpa_driver_nl80211_init - Initialize nl80211 driver interface
17286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @ctx: context to be used when calling wpa_supplicant functions,
17296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * e.g., wpa_supplicant_event()
17306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @ifname: interface name, e.g., wlan0
17316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @global_priv: private driver global data from global_init()
17326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Returns: Pointer to private data, %NULL on failure
17336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */
17346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
17356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				      void *global_priv)
17366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
17376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return wpa_driver_nl80211_drv_init(ctx, ifname, global_priv, 0, NULL,
17386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					   NULL);
17396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
17408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_register_frame(struct i802_bss *bss,
17436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  struct nl_handle *nl_handle,
17446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  u16 type, const u8 *match, size_t match_len)
17456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
17466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
17476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
17486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
17496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	char buf[30];
17508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	buf[0] = '\0';
17526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_snprintf_hex(buf, sizeof(buf), match, match_len);
17536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x (%s) nl_handle=%p match=%s",
17546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   type, fc2str(type), nl_handle, buf);
175534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
17566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REGISTER_ACTION)) ||
17576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, type) ||
17586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_FRAME_MATCH, match_len, match)) {
17596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
17606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
17618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL);
17646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret) {
17656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
17666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "failed (type=%u): ret=%d (%s)",
17676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   type, ret, strerror(-ret));
17686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
17696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    match, match_len);
17706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
17716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
17728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
17738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
17768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
17776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss->nl_mgmt) {
17786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
17796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "already on! (nl_mgmt=%p)", bss->nl_mgmt);
17806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
17816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
17828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	bss->nl_mgmt = nl_create_handle(bss->nl_cb, "mgmt");
17846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss->nl_mgmt == NULL)
17856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
17868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 0;
17886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
17898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void nl80211_mgmt_handle_register_eloop(struct i802_bss *bss)
17926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
17936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl80211_register_eloop_read(&bss->nl_mgmt,
17946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    wpa_driver_nl80211_event_receive,
17956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    bss->nl_cb);
17966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
17976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
17988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_register_action_frame(struct i802_bss *bss,
18006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					 const u8 *match, size_t match_len)
18016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
18026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
18036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return nl80211_register_frame(bss, bss->nl_mgmt,
18046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				      type, match, match_len);
18058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
18068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
18098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
18106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
18116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret = 0;
18128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_alloc_mgmt_handle(bss))
18146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
18156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
18166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   "handle %p", bss->nl_mgmt);
18178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
18196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
18206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
18216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/* register for any AUTH message */
18226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0);
18238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_INTERWORKING
18266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* QoS Map Configure */
18276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0)
18286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
18296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_INTERWORKING */
18306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING)
18316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* GAS Initial Request */
18326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
18336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
18346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* GAS Initial Response */
18356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0)
18366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
18376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* GAS Comeback Request */
18386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0)
18396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
18406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* GAS Comeback Response */
18416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0)
18426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
18436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* Protected GAS Initial Request */
18446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0a", 2) < 0)
18456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
18466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* Protected GAS Initial Response */
18476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0b", 2) < 0)
18486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
18496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* Protected GAS Comeback Request */
18506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0c", 2) < 0)
18516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
18526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* Protected GAS Comeback Response */
18536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x09\x0d", 2) < 0)
18546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
18556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_P2P || CONFIG_INTERWORKING */
18566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_P2P
18576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* P2P Public Action */
18586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss,
18596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  (u8 *) "\x04\x09\x50\x6f\x9a\x09",
18606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  6) < 0)
18616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
18626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* P2P Action */
18636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss,
18646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  (u8 *) "\x7f\x50\x6f\x9a\x09",
18656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  5) < 0)
18666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
18676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_P2P */
18686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_IEEE80211W
18696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* SA Query Response */
18706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
18716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
18726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_IEEE80211W */
18736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_TDLS
18746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
18756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/* TDLS Discovery Response */
18766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) <
18776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    0)
18786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			ret = -1;
18798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_TDLS */
18818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* FT Action frames */
18836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
18846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
18856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	else
18866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
18876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
18888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* WNM - BSS Transition Management Request */
18906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
18916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
18926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* WNM-Sleep Mode Response */
18936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
18946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
18958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_HS20
18976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* WNM-Notification */
18986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x1a", 2) < 0)
18996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
19006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_HS20 */
19018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* WMM-AC ADDTS Response */
19036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x11\x01", 2) < 0)
19046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
19058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* WMM-AC DELTS */
19076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x11\x02", 2) < 0)
19086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
19096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
19106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* Radio Measurement - Neighbor Report Response */
19116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x05\x05", 2) < 0)
19126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
19136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
19146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* Radio Measurement - Link Measurement Request */
19156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if ((drv->capa.rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION) &&
19166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (nl80211_register_action_frame(bss, (u8 *) "\x05\x02", 2) < 0))
19176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
19186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
19196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl80211_mgmt_handle_register_eloop(bss);
19206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
19216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
19228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_mgmt_subscribe_mesh(struct i802_bss *bss)
19268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
19276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret = 0;
19288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_alloc_mgmt_handle(bss))
19306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
19318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG,
19336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   "nl80211: Subscribe to mgmt frames with mesh handle %p",
19346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   bss->nl_mgmt);
19358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* Auth frames for mesh SAE */
19376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_frame(bss, bss->nl_mgmt,
19386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   (WLAN_FC_TYPE_MGMT << 2) |
19396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   (WLAN_FC_STYPE_AUTH << 4),
19406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   NULL, 0) < 0)
19416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
19428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* Mesh peering open */
19446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x01", 2) < 0)
19456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
19466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* Mesh peering confirm */
19476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x02", 2) < 0)
19486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
19496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* Mesh peering close */
19506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x03", 2) < 0)
19516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = -1;
19528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl80211_mgmt_handle_register_eloop(bss);
19541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
19556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
19561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
19571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
19581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
19596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_register_spurious_class3(struct i802_bss *bss)
19601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
19611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_msg *msg;
19626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
19631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
19646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UNEXPECTED_FRAME);
19656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv(bss->drv->global, bss->nl_mgmt, msg, NULL, NULL);
19666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret) {
19676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
19686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "failed: ret=%d (%s)",
19696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   ret, strerror(-ret));
19706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
19716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
19728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
19768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
19776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	static const int stypes[] = {
19786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		WLAN_FC_STYPE_AUTH,
19796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		WLAN_FC_STYPE_ASSOC_REQ,
19806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		WLAN_FC_STYPE_REASSOC_REQ,
19816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		WLAN_FC_STYPE_DISASSOC,
19826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		WLAN_FC_STYPE_DEAUTH,
19836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		WLAN_FC_STYPE_ACTION,
19846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		WLAN_FC_STYPE_PROBE_REQ,
19856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/* Beacon doesn't work as mac80211 doesn't currently allow
19866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * it, but it wouldn't really be the right thing anyway as
19876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * it isn't per interface ... maybe just dump the scan
19886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * results periodically for OLBC?
19896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */
19906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/* WLAN_FC_STYPE_BEACON, */
19918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
19926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	unsigned int i;
19938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_alloc_mgmt_handle(bss))
19956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
19966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
19976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   "handle %p", bss->nl_mgmt);
19988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	for (i = 0; i < ARRAY_SIZE(stypes); i++) {
20006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nl80211_register_frame(bss, bss->nl_mgmt,
20016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					   (WLAN_FC_TYPE_MGMT << 2) |
20026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					   (stypes[i] << 4),
20036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					   NULL, 0) < 0) {
20046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto out_err;
20056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
20068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
20078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_spurious_class3(bss))
20096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto out_err;
20108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_get_wiphy_data_ap(bss) == NULL)
20126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto out_err;
20138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl80211_mgmt_handle_register_eloop(bss);
20156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 0;
20168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtout_err:
20186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl_destroy_handles(&bss->nl_mgmt);
20196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return -1;
20208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
20218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
20248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
20256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_alloc_mgmt_handle(bss))
20266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
20276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
20286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   "handle %p (device SME)", bss->nl_mgmt);
20298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl80211_register_frame(bss, bss->nl_mgmt,
20316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   (WLAN_FC_TYPE_MGMT << 2) |
20326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   (WLAN_FC_STYPE_ACTION << 4),
20336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   NULL, 0) < 0)
20346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto out_err;
2035c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt
20366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl80211_mgmt_handle_register_eloop(bss);
20376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 0;
20388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtout_err:
20406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl_destroy_handles(&bss->nl_mgmt);
20416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return -1;
20428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
20438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason)
20468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
20476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss->nl_mgmt == NULL)
2048c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		return;
20496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
20506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   "(%s)", bss->nl_mgmt, reason);
20516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl80211_destroy_eloop_handle(&bss->nl_mgmt);
2052c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt
20536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl80211_put_wiphy_data_ap(bss);
20546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
20558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
20586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
20596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
20606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
20618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
20636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void nl80211_del_p2pdev(struct i802_bss *bss)
20646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
20656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
20666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
2067d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
20686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_INTERFACE);
20696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
20701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
20716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
20726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   bss->ifname, (long long unsigned int) bss->wdev_id,
20736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   strerror(-ret));
20741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
20751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
20761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
20776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_set_p2pdev(struct i802_bss *bss, int start)
20781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
20796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
20806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
20811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
20826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_cmd_msg(bss, 0, start ? NL80211_CMD_START_P2P_DEVICE :
20836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			      NL80211_CMD_STOP_P2P_DEVICE);
20846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
20851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
20866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
20876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   start ? "Start" : "Stop",
20886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   bss->ifname, (long long unsigned int) bss->wdev_id,
20896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   strerror(-ret));
20906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
20911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
20921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
20931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
20946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int i802_set_iface_flags(struct i802_bss *bss, int up)
2095d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt{
20966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	enum nl80211_iftype nlmode;
2097d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
20986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nlmode = nl80211_get_ifmode(bss);
20996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
21006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return linux_set_iface_flags(bss->drv->global->ioctl_sock,
21016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					     bss->ifname, up);
2102d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	}
2103d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
21046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* P2P Device has start/stop which is equivalent */
21056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return nl80211_set_p2pdev(bss, up);
21065393a0f77c5281735888bd9dcf8d8abeb5961461Dmitry Shmidt}
21075393a0f77c5281735888bd9dcf8d8abeb5961461Dmitry Shmidt
21085393a0f77c5281735888bd9dcf8d8abeb5961461Dmitry Shmidt
21097f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt#ifdef CONFIG_TESTING_OPTIONS
21107f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidtstatic int qca_vendor_test_cmd_handler(struct nl_msg *msg, void *arg)
21117f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt{
21127f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	/* struct wpa_driver_nl80211_data *drv = arg; */
21137f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
21147f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
21157f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
21167f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
21177f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	wpa_printf(MSG_DEBUG,
21187f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		   "nl80211: QCA vendor test command response received");
21197f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
21207f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
21217f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
21227f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	if (!tb[NL80211_ATTR_VENDOR_DATA]) {
21237f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: No vendor data attribute");
21247f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		return NL_SKIP;
21257f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	}
21267f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
21277f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	wpa_hexdump(MSG_DEBUG,
21287f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		    "nl80211: Received QCA vendor test command response",
21297f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		    nla_data(tb[NL80211_ATTR_VENDOR_DATA]),
21307f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		    nla_len(tb[NL80211_ATTR_VENDOR_DATA]));
21317f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
21327f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	return NL_SKIP;
21337f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt}
21347f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt#endif /* CONFIG_TESTING_OPTIONS */
21357f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
21367f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
21377f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidtstatic void qca_vendor_test(struct wpa_driver_nl80211_data *drv)
21387f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt{
21397f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt#ifdef CONFIG_TESTING_OPTIONS
21407f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	struct nl_msg *msg;
21417f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	struct nlattr *params;
21427f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	int ret;
21437f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
21447f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
21457f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
21467f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
21477f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt			QCA_NL80211_VENDOR_SUBCMD_TEST) ||
21487f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	    !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
21497f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	    nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_TEST, 123)) {
21507f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		nlmsg_free(msg);
21517f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		return;
21527f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	}
21537f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	nla_nest_end(msg, params);
21547f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
21557f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, qca_vendor_test_cmd_handler, drv);
21567f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	wpa_printf(MSG_DEBUG,
21577f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		   "nl80211: QCA vendor test command returned %d (%s)",
21587f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		   ret, strerror(-ret));
21597f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt#endif /* CONFIG_TESTING_OPTIONS */
21607f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt}
21617f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
21627f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
21636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int
21646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtwpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
21656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   const u8 *set_addr, int first,
21666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   const char *driver_params)
2167f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt{
21686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = drv->first_bss;
21696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int send_rfkill_event = 0;
21706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	enum nl80211_iftype nlmode;
2171f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
21726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->ifindex = if_nametoindex(bss->ifname);
21736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	bss->ifindex = drv->ifindex;
21746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	bss->wdev_id = drv->global->if_add_wdevid;
21756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	bss->wdev_id_set = drv->global->if_add_wdevid_set;
2176f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
21776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	bss->if_dynamic = drv->ifindex == drv->global->if_add_ifindex;
21786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	bss->if_dynamic = bss->if_dynamic || drv->global->if_add_wdevid_set;
21796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->global->if_add_wdevid_set = 0;
2180f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
21816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!bss->if_dynamic && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
21826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		bss->static_ap = 1;
2183f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
21846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (wpa_driver_nl80211_capa(drv))
21856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
2186f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
21876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (driver_params && nl80211_set_param(bss, driver_params) < 0)
21886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
2189f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
21906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
21916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   bss->ifname, drv->phyname);
2192ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
21936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (set_addr &&
21946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) ||
21956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
21966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				set_addr)))
21976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
2198ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
21996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (first && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
22006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		drv->start_mode_ap = 1;
2201051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
22026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->hostapd || bss->static_ap)
22036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmode = NL80211_IFTYPE_AP;
22046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	else if (bss->if_dynamic)
22056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmode = nl80211_get_ifmode(bss);
22066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	else
22076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmode = NL80211_IFTYPE_STATION;
2208051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
22096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (wpa_driver_nl80211_set_mode(bss, nlmode) < 0) {
22106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Could not configure driver mode");
22116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
2212051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt	}
2213ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
22146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
22156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl80211_get_macaddr(bss);
22166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
22176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!rfkill_is_blocked(drv->rfkill)) {
22186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		int ret = i802_set_iface_flags(bss, 1);
22196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (ret) {
22206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_ERROR, "nl80211: Could not set "
22216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "interface '%s' UP", bss->ifname);
22226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return ret;
22236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
22246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
22256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return ret;
22266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else {
22276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable "
22286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "interface '%s' due to rfkill", bss->ifname);
22296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
22306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return 0;
22316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		drv->if_disabled = 1;
22326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		send_rfkill_event = 1;
2233ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	}
2234ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
22356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!drv->hostapd)
22366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
22376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				       1, IF_OPER_DORMANT);
2238ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
22396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
22406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			       bss->addr))
22416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
22426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_memcpy(drv->perm_addr, bss->addr, ETH_ALEN);
22431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
22446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (send_rfkill_event) {
22456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
22466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				       drv, drv->ctx);
22476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
22481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
22497f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	if (drv->vendor_cmd_test_avail)
22507f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		qca_vendor_test(drv);
22517f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
22526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 0;
22536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
22548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
22566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
22576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
22586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
22596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
22606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
22616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   drv->ifindex);
22626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON);
22636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
22641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
22651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
22661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
22676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt/**
22686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
22696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * @bss: Pointer to private nl80211 data from wpa_driver_nl80211_init()
22706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt *
22716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * Shut down driver interface and processing of driver events. Free
22726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt * private data buffer if one was allocated in wpa_driver_nl80211_init().
22736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt */
22746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void wpa_driver_nl80211_deinit(struct i802_bss *bss)
2275cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt{
22766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
2277cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
22786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_INFO, "nl80211: deinit ifname=%s disabled_11b_rates=%d",
22796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   bss->ifname, drv->disabled_11b_rates);
2280cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
22816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	bss->in_deinit = 1;
22826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->data_tx_status)
22836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		eloop_unregister_read_sock(drv->eapol_tx_sock);
22846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->eapol_tx_sock >= 0)
22856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		close(drv->eapol_tx_sock);
2286cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
22876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss->nl_preq)
22886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_driver_nl80211_probe_req_report(bss, 0);
22896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss->added_if_into_bridge) {
22906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
22916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    bss->ifname) < 0)
22926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
22936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "interface %s from bridge %s: %s",
22946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   bss->ifname, bss->brname, strerror(errno));
22956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (drv->rtnl_sk)
22966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			nl80211_handle_destroy(drv->rtnl_sk);
2297cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
22986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss->added_bridge) {
22996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
23006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  0) < 0)
23016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_INFO,
23026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "nl80211: Could not set bridge %s down",
23036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   bss->brname);
23046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
23056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
23066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "bridge %s: %s",
23076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   bss->brname, strerror(errno));
2308cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
2309cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
23106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl80211_remove_monitor_interface(drv);
2311cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
23126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (is_ap_interface(drv->nlmode))
23136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_driver_nl80211_del_beacon(drv);
2314cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
23156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->eapol_sock >= 0) {
23166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		eloop_unregister_read_sock(drv->eapol_sock);
23176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		close(drv->eapol_sock);
2318cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt	}
2319cf32e60fa7e0d33fe1551a6dba8dcbbec47ea50eDmitry Shmidt
23206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->if_indices != drv->default_if_indices)
23216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		os_free(drv->if_indices);
2322fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
23236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->disabled_11b_rates)
23246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl80211_disable_11b_rates(drv, drv->ifindex, 0);
2325fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
23266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
23276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			       IF_OPER_UP);
23286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	eloop_cancel_timeout(wpa_driver_nl80211_send_rfkill, drv, drv->ctx);
23296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	rfkill_deinit(drv->rfkill);
2330fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
23316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
2332fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
23336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!drv->start_iface_up)
23346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		(void) i802_set_iface_flags(bss, 0);
2335fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
23366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->addr_changed) {
23376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
23386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  0) < 0) {
23396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG,
23406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "nl80211: Could not set interface down to restore permanent MAC address");
23416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
23426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
23436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				       drv->perm_addr) < 0) {
23446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG,
23456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "nl80211: Could not restore permanent MAC address");
23466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
2347fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
2348fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
23496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
23506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (!drv->hostapd || !drv->start_mode_ap)
23516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_driver_nl80211_set_mode(bss,
23526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt						    NL80211_IFTYPE_STATION);
23536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl80211_mgmt_unsubscribe(bss, "deinit");
23546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else {
23556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl80211_mgmt_unsubscribe(bss, "deinit");
23566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl80211_del_p2pdev(bss);
2357fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
2358fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
23596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl80211_destroy_bss(drv->first_bss);
23606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
23616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_free(drv->filter_ssids);
23626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
23636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_free(drv->auth_ie);
23646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
23656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->in_interface_list)
23666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		dl_list_del(&drv->list);
23676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
23686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_free(drv->extended_capa);
23696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_free(drv->extended_capa_mask);
23706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_free(drv->first_bss);
23716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_free(drv);
2372fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt}
2373fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
2374fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
23756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic u32 wpa_alg_to_cipher_suite(enum wpa_alg alg, size_t key_len)
23767dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt{
23776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	switch (alg) {
23786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_ALG_WEP:
23796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (key_len == 5)
23806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return WLAN_CIPHER_SUITE_WEP40;
23816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_CIPHER_SUITE_WEP104;
23826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_ALG_TKIP:
23836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_CIPHER_SUITE_TKIP;
23846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_ALG_CCMP:
23856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_CIPHER_SUITE_CCMP;
23866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_ALG_GCMP:
23876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_CIPHER_SUITE_GCMP;
23886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_ALG_CCMP_256:
23896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_CIPHER_SUITE_CCMP_256;
23906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_ALG_GCMP_256:
23916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_CIPHER_SUITE_GCMP_256;
23926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_ALG_IGTK:
23936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_CIPHER_SUITE_AES_CMAC;
23946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_ALG_BIP_GMAC_128:
23956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_CIPHER_SUITE_BIP_GMAC_128;
23966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_ALG_BIP_GMAC_256:
23976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_CIPHER_SUITE_BIP_GMAC_256;
23986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_ALG_BIP_CMAC_256:
23996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_CIPHER_SUITE_BIP_CMAC_256;
24006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_ALG_SMS4:
24016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_CIPHER_SUITE_SMS4;
24026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_ALG_KRK:
24036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_CIPHER_SUITE_KRK;
24046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_ALG_NONE:
24056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_ALG_PMK:
24066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Unexpected encryption algorithm %d",
24076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   alg);
24086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return 0;
24096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
24107dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt
24116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_ERROR, "nl80211: Unsupported encryption algorithm %d",
24126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   alg);
24136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 0;
24146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
24157dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt
24167dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt
24176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic u32 wpa_cipher_to_cipher_suite(unsigned int cipher)
24186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
24196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	switch (cipher) {
24206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_CIPHER_CCMP_256:
24216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_CIPHER_SUITE_CCMP_256;
24226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_CIPHER_GCMP_256:
24236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_CIPHER_SUITE_GCMP_256;
24246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_CIPHER_CCMP:
24256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_CIPHER_SUITE_CCMP;
24266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_CIPHER_GCMP:
24276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_CIPHER_SUITE_GCMP;
24286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_CIPHER_TKIP:
24296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_CIPHER_SUITE_TKIP;
24306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_CIPHER_WEP104:
24316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_CIPHER_SUITE_WEP104;
24326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_CIPHER_WEP40:
24336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_CIPHER_SUITE_WEP40;
24346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_CIPHER_GTK_NOT_USED:
24356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return WLAN_CIPHER_SUITE_NO_GROUP_ADDR;
24367dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt	}
24377dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt
24386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 0;
24396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
24407dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt
24417dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt
24426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_cipher_to_cipher_suites(unsigned int ciphers, u32 suites[],
24436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				       int max_suites)
24446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
24456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int num_suites = 0;
24466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
24476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP_256)
24486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP_256;
24496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP_256)
24506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP_256;
24516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (num_suites < max_suites && ciphers & WPA_CIPHER_CCMP)
24526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
24536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (num_suites < max_suites && ciphers & WPA_CIPHER_GCMP)
24546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP;
24556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (num_suites < max_suites && ciphers & WPA_CIPHER_TKIP)
24566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP;
24576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP104)
24586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104;
24596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (num_suites < max_suites && ciphers & WPA_CIPHER_WEP40)
24606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40;
24616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
24626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return num_suites;
24637dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt}
24647dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt
24657dba0e5708da7276a43a44cf479aa743564e15b9Dmitry Shmidt
24666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
24676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  const u8 *key, size_t key_len)
24681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
24696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
24706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
2471a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
24726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD))
24736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return 0;
247434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
24756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
24766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
24776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
24786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY) ||
24796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_VENDOR_DATA, key_len, key)) {
24806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl80211_nlmsg_clear(msg);
24816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
24826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
24838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
24846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
24856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret) {
24866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
24876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Key management set key failed: ret=%d (%s)",
24886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   ret, strerror(-ret));
24891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
24906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
24916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
24921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
24931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
24941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
24956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
24966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				      enum wpa_alg alg, const u8 *addr,
24976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				      int key_idx, int set_tx,
24986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				      const u8 *seq, size_t seq_len,
24996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				      const u8 *key, size_t key_len)
25001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
25016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
25026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ifindex;
25031d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt	struct nl_msg *msg = NULL;
25046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
25056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int tdls = 0;
25061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* Ignore for P2P Device */
25086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
25096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return 0;
25101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ifindex = if_nametoindex(ifname);
25126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d "
25136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   "set_tx=%d seq_len=%lu key_len=%lu",
25146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   __func__, ifindex, ifname, alg, addr, key_idx, set_tx,
25156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   (unsigned long) seq_len, (unsigned long) key_len);
25166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_TDLS
25176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (key_idx == -1) {
25186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		key_idx = 0;
25196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		tdls = 1;
25206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
25216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_TDLS */
2522a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
25236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (alg == WPA_ALG_PMK &&
25246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
25256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "%s: calling issue_key_mgmt_set_key",
25266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   __func__);
25276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = issue_key_mgmt_set_key(drv, key, key_len);
25286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return ret;
25291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
25301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (alg == WPA_ALG_NONE) {
25326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
25336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (!msg)
25346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -ENOBUFS;
25356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else {
25361d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt		u32 suite;
25371d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt
25381d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt		suite = wpa_alg_to_cipher_suite(alg, key_len);
25391d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt		if (!suite)
25401d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt			goto fail;
25416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
25426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (!msg ||
25436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    nla_put(msg, NL80211_ATTR_KEY_DATA, key_len, key) ||
25441d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt		    nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER, suite))
25456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
25466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len);
25476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
25481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (seq && seq_len) {
25506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq))
25516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
25526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ", seq, seq_len);
25536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
25541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (addr && !is_broadcast_ether_addr(addr)) {
25566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "   addr=" MACSTR, MAC2STR(addr));
25576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
25586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
25591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (alg != WPA_ALG_WEP && key_idx && !set_tx) {
25616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG, "   RSN IBSS RX GTK");
25626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (nla_put_u32(msg, NL80211_ATTR_KEY_TYPE,
25636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					NL80211_KEYTYPE_GROUP))
25646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
25656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
25666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else if (addr && is_broadcast_ether_addr(addr)) {
25676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		struct nlattr *types;
25681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "   broadcast key");
25701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
25726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (!types ||
25736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
25746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
25756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nla_nest_end(msg, types);
25761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
25776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
25786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
25791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, key ? (void *) -1 : NULL);
25816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
25826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = 0;
25836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret)
25846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s)",
25856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   ret, strerror(-ret));
25861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/*
25886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * If we failed or don't need to set the default TX key (below),
25896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * we're done here.
25906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 */
25916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret || !set_tx || alg == WPA_ALG_NONE || tdls)
25926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return ret;
25936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (is_ap_interface(drv->nlmode) && addr &&
25946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    !is_broadcast_ether_addr(addr))
25956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return ret;
25961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
25986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg ||
25996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx) ||
2600807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	    nla_put_flag(msg, (alg == WPA_ALG_IGTK ||
2601807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt			       alg == WPA_ALG_BIP_GMAC_128 ||
2602807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt			       alg == WPA_ALG_BIP_GMAC_256 ||
2603807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt			       alg == WPA_ALG_BIP_CMAC_256) ?
26046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 NL80211_ATTR_KEY_DEFAULT_MGMT :
26056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 NL80211_ATTR_KEY_DEFAULT))
26066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
26076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (addr && is_broadcast_ether_addr(addr)) {
26086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		struct nlattr *types;
26091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
26106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
26116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (!types ||
26126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
26136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
26146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nla_nest_end(msg, types);
26156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else if (addr) {
26166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		struct nlattr *types;
261734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
26186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
26196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (!types ||
26206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST))
26216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
26226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nla_nest_end(msg, types);
26238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
26248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
26266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret == -ENOENT)
26276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = 0;
26286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret)
26296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: set_key default failed; "
26306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "err=%d %s)", ret, strerror(-ret));
26316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
26326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
26336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
26346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl80211_nlmsg_clear(msg);
26356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nlmsg_free(msg);
26366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return -ENOBUFS;
26378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
26388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
26416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		      int key_idx, int defkey,
26426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		      const u8 *seq, size_t seq_len,
26436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		      const u8 *key, size_t key_len)
26448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
26456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY);
26461d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt	u32 suite;
26471d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt
26486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!key_attr)
26496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
26508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26511d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt	suite = wpa_alg_to_cipher_suite(alg, key_len);
26521d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt	if (!suite)
26531d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt		return -1;
26541d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt
26556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (defkey && alg == WPA_ALG_IGTK) {
26566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_flag(msg, NL80211_KEY_DEFAULT_MGMT))
26576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -1;
26586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else if (defkey) {
26596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_flag(msg, NL80211_KEY_DEFAULT))
26606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -1;
266168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	}
26626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
26636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_put_u8(msg, NL80211_KEY_IDX, key_idx) ||
26641d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt	    nla_put_u32(msg, NL80211_KEY_CIPHER, suite) ||
26656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (seq && seq_len &&
26666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put(msg, NL80211_KEY_SEQ, seq_len, seq)) ||
26676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_KEY_DATA, key_len, key))
26686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
26696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
26706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nla_nest_end(msg, key_attr);
26716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
26726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 0;
26738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
26748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_set_conn_keys(struct wpa_driver_associate_params *params,
26776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				 struct nl_msg *msg)
26788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
26796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int i, privacy = 0;
26806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *nl_keys, *nl_key;
26818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	for (i = 0; i < 4; i++) {
26836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (!params->wep_key[i])
26846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			continue;
26856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		privacy = 1;
26866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		break;
26876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
26886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->wps == WPS_MODE_PRIVACY)
26896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		privacy = 1;
26906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->pairwise_suite &&
26916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    params->pairwise_suite != WPA_CIPHER_NONE)
26926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		privacy = 1;
26938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!privacy)
26956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return 0;
26968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_put_flag(msg, NL80211_ATTR_PRIVACY))
26986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
26998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
27016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!nl_keys)
27026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
27038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	for (i = 0; i < 4; i++) {
27056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (!params->wep_key[i])
27066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			continue;
27078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl_key = nla_nest_start(msg, i);
27096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (!nl_key ||
27106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    nla_put(msg, NL80211_KEY_DATA, params->wep_key_len[i],
27116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    params->wep_key[i]) ||
27126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    nla_put_u32(msg, NL80211_KEY_CIPHER,
27136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				params->wep_key_len[i] == 5 ?
27146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				WLAN_CIPHER_SUITE_WEP40 :
27156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				WLAN_CIPHER_SUITE_WEP104) ||
27166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    nla_put_u8(msg, NL80211_KEY_IDX, i) ||
27176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    (i == params->wep_tx_keyidx &&
27186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		     nla_put_flag(msg, NL80211_KEY_DEFAULT)))
27196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -ENOBUFS;
2720cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
27216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nla_nest_end(msg, nl_key);
2722cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	}
27236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nla_nest_end(msg, nl_keys);
27246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
27256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 0;
2726cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt}
2727cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
2728cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt
27296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
27306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    const u8 *addr, int cmd, u16 reason_code,
27316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    int local_state_change)
2732cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt{
2733cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int ret;
27342f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct nl_msg *msg;
27352f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
27366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_drv_msg(drv, 0, cmd)) ||
27376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code) ||
27386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
27396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (local_state_change &&
27406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_flag(msg, NL80211_ATTR_LOCAL_STATE_CHANGE))) {
27416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
27426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
27436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
27442f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
27456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
27466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret) {
27476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_dbg(drv->ctx, MSG_DEBUG,
27486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			"nl80211: MLME command failed: reason=%u ret=%d (%s)",
27496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			reason_code, ret, strerror(-ret));
27502f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
27516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
27522f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt}
27532f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
27542f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
27556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
27566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					 int reason_code)
27572f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt{
27586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
2759413dde71f7bc166de54229f337c24b61f4d909fdDmitry Shmidt
27606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
27616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl80211_mark_disconnected(drv);
27626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* Disconnect command doesn't need BSSID - it uses cached value */
27636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
27646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				      reason_code, 0);
27656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/*
27666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * For locally generated disconnect, supplicant already generates a
27676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * DEAUTH event, so ignore the event from NL80211.
27686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 */
27696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->ignore_next_local_disconnect = ret == 0;
27702f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
27716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
27722f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt}
27732f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
27742f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
27756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
27766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					     const u8 *addr, int reason_code)
27772f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt{
27786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
27796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
27802f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
27816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
27826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl80211_mark_disconnected(drv);
27836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return nl80211_leave_ibss(drv, 1);
27842f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
27856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
27866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return wpa_driver_nl80211_disconnect(drv, reason_code);
27876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
27886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   __func__, MAC2STR(addr), reason_code);
27896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl80211_mark_disconnected(drv);
27906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
27916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				      reason_code, 0);
27926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/*
27936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * For locally generated deauthenticate, supplicant already generates a
27946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * DEAUTH event, so ignore the event from NL80211.
27956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 */
27966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->ignore_next_local_deauth = ret == 0;
27976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
27982f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt}
27992f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
28002f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
28016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
28026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				     struct wpa_driver_auth_params *params)
28032f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt{
28042f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	int i;
28052f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
28066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->auth_freq = params->freq;
28076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->auth_alg = params->auth_alg;
28086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->auth_wep_tx_keyidx = params->wep_tx_keyidx;
28096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->auth_local_state_change = params->local_state_change;
28106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->auth_p2p = params->p2p;
2811fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
28126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->bssid)
28136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		os_memcpy(drv->auth_bssid_, params->bssid, ETH_ALEN);
28146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	else
28156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		os_memset(drv->auth_bssid_, 0, ETH_ALEN);
2816fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
28176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->ssid) {
28186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		os_memcpy(drv->auth_ssid, params->ssid, params->ssid_len);
28196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		drv->auth_ssid_len = params->ssid_len;
28206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else
28216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		drv->auth_ssid_len = 0;
2822fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
2823fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
28246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_free(drv->auth_ie);
28256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->auth_ie = NULL;
28266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->auth_ie_len = 0;
28276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->ie) {
28286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		drv->auth_ie = os_malloc(params->ie_len);
28296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (drv->auth_ie) {
28306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			os_memcpy(drv->auth_ie, params->ie, params->ie_len);
28316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			drv->auth_ie_len = params->ie_len;
28322f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		}
28332f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
28342f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
28356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	for (i = 0; i < 4; i++) {
28366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (params->wep_key[i] && params->wep_key_len[i] &&
28376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    params->wep_key_len[i] <= 16) {
28386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			os_memcpy(drv->auth_wep_key[i], params->wep_key[i],
28396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  params->wep_key_len[i]);
28406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			drv->auth_wep_key_len[i] = params->wep_key_len[i];
28416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		} else
28426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			drv->auth_wep_key_len[i] = 0;
28432f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
28442f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt}
28452f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
28462f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
28476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void nl80211_unmask_11b_rates(struct i802_bss *bss)
2848b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt{
28496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
2850b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt
28516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (is_p2p_net_interface(drv->nlmode) || !drv->disabled_11b_rates)
2852b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt		return;
2853b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt
28546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/*
28556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * Looks like we failed to unmask 11b rates previously. This could
28566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * happen, e.g., if the interface was down at the point in time when a
28576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * P2P group was terminated.
28586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 */
28596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG,
28606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   "nl80211: Interface %s mode is for non-P2P, but 11b rates were disabled - re-enable them",
28616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   bss->ifname);
28626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl80211_disable_11b_rates(drv, drv->ifindex, 0);
2863b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt}
2864b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt
2865b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt
28666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_nl80211_authenticate(
28676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss, struct wpa_driver_auth_params *params)
28682f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt{
28696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
28706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret = -1, i;
28716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
28726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	enum nl80211_auth_type type;
28736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	enum nl80211_iftype nlmode;
28746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int count = 0;
28756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int is_retry;
28768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl80211_unmask_11b_rates(bss);
28788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	is_retry = drv->retry_auth;
28806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->retry_auth = 0;
28816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->ignore_deauth_event = 0;
28821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
28836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl80211_mark_disconnected(drv);
28846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_memset(drv->auth_bssid, 0, ETH_ALEN);
28856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->bssid)
28866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
28876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	else
28886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
28896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* FIX: IBSS mode */
28906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nlmode = params->p2p ?
28916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
28926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->nlmode != nlmode &&
28936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    wpa_driver_nl80211_set_mode(bss, nlmode) < 0)
28946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
28951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
28966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtretry:
28976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
28986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   drv->ifindex);
28998bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
29006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_AUTHENTICATE);
29016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg)
29026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
29038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	for (i = 0; i < 4; i++) {
29056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (!params->wep_key[i])
29066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			continue;
29076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_driver_nl80211_set_key(bss->ifname, bss, WPA_ALG_WEP,
29086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					   NULL, i,
29096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					   i == params->wep_tx_keyidx, NULL, 0,
29106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					   params->wep_key[i],
29116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					   params->wep_key_len[i]);
29126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (params->wep_tx_keyidx != i)
29136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			continue;
29146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
29156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			       params->wep_key[i], params->wep_key_len[i]))
29166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
29171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
29181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
29196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->bssid) {
29206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * bssid=" MACSTR,
29216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   MAC2STR(params->bssid));
29226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
29236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
2924444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	}
29256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->freq) {
29266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
29276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq))
29286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
2929fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
29306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->ssid) {
29316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
29326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  params->ssid, params->ssid_len);
29336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
29346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    params->ssid))
29356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
2936fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
29376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "  * IEs", params->ie, params->ie_len);
29386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->ie &&
29396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_IE, params->ie_len, params->ie))
29406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
29416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->sae_data) {
29426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "  * SAE data", params->sae_data,
29436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    params->sae_data_len);
29446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_SAE_DATA, params->sae_data_len,
29456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    params->sae_data))
29466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
29476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
29486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->auth_alg & WPA_AUTH_ALG_OPEN)
29496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		type = NL80211_AUTHTYPE_OPEN_SYSTEM;
29506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
29516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		type = NL80211_AUTHTYPE_SHARED_KEY;
29526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
29536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		type = NL80211_AUTHTYPE_NETWORK_EAP;
29546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	else if (params->auth_alg & WPA_AUTH_ALG_FT)
29556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		type = NL80211_AUTHTYPE_FT;
29566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	else if (params->auth_alg & WPA_AUTH_ALG_SAE)
29576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		type = NL80211_AUTHTYPE_SAE;
29582f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	else
29596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
29606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "  * Auth Type %d", type);
29616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
29626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
29636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->local_state_change) {
29646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * Local state change only");
29656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_flag(msg, NL80211_ATTR_LOCAL_STATE_CHANGE))
29666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
29672f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
29682f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
29696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
29706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = NULL;
29716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret) {
29726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_dbg(drv->ctx, MSG_DEBUG,
29736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			"nl80211: MLME command failed (auth): ret=%d (%s)",
29746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			ret, strerror(-ret));
29756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		count++;
29766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (ret == -EALREADY && count == 1 && params->bssid &&
29776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    !params->local_state_change) {
29786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			/*
29796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 * mac80211 does not currently accept new
29806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 * authentication if we are already authenticated. As a
29816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 * workaround, force deauthentication and try again.
29826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 */
29836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Retry authentication "
29846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "after forced deauthentication");
29856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			drv->ignore_deauth_event = 1;
29866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_driver_nl80211_deauthenticate(
29876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				bss, params->bssid,
29886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				WLAN_REASON_PREV_AUTH_NOT_VALID);
29896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			nlmsg_free(msg);
29906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto retry;
29916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
299251b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt
29936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (ret == -ENOENT && params->freq && !is_retry) {
29946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			/*
29956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 * cfg80211 has likely expired the BSS entry even
29966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 * though it was previously available in our internal
29976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 * BSS table. To recover quickly, start a single
29986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 * channel scan on the specified channel.
29996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 */
30006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			struct wpa_driver_scan_params scan;
30016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			int freqs[2];
300251b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt
30036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			os_memset(&scan, 0, sizeof(scan));
30046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			scan.num_ssids = 1;
30056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (params->ssid) {
30066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				scan.ssids[0].ssid = params->ssid;
30076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				scan.ssids[0].ssid_len = params->ssid_len;
30086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			}
30096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			freqs[0] = params->freq;
30106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			freqs[1] = 0;
30116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			scan.freqs = freqs;
30126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Trigger single "
30136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "channel scan to refresh cfg80211 BSS "
30146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "entry");
30156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			ret = wpa_driver_nl80211_scan(bss, &scan);
30166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (ret == 0) {
30176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				nl80211_copy_auth_params(drv, params);
30186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				drv->scan_for_auth = 1;
30196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			}
30206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		} else if (is_retry) {
30216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			/*
30226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 * Need to indicate this with an event since the return
30236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 * value from the retry is not delivered to core code.
30246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 */
30256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			union wpa_event_data event;
30266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Authentication retry "
30276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "failed");
30286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			os_memset(&event, 0, sizeof(event));
30296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			os_memcpy(event.timeout_event.addr, drv->auth_bssid_,
30306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  ETH_ALEN);
30316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT,
30326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					     &event);
30336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
30346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else {
30356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
30366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Authentication request send successfully");
30376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
3038fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
30396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
30408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
30416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
30428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
30438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv)
30468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
30476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_auth_params params;
30486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = drv->first_bss;
30496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int i;
30508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
3052ad266fb3da6083126e7619e525153839b918aa44Dmitry Shmidt
30536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_memset(&params, 0, sizeof(params));
30546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	params.freq = drv->auth_freq;
30556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	params.auth_alg = drv->auth_alg;
30566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	params.wep_tx_keyidx = drv->auth_wep_tx_keyidx;
30576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	params.local_state_change = drv->auth_local_state_change;
30586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	params.p2p = drv->auth_p2p;
3059a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
30606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!is_zero_ether_addr(drv->auth_bssid_))
30616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		params.bssid = drv->auth_bssid_;
30628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->auth_ssid_len) {
30646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		params.ssid = drv->auth_ssid;
30656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		params.ssid_len = drv->auth_ssid_len;
306661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
306761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
30686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	params.ie = drv->auth_ie;
30696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	params.ie_len = drv->auth_ie_len;
30701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
30716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	for (i = 0; i < 4; i++) {
30726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (drv->auth_wep_key_len[i]) {
30736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			params.wep_key[i] = drv->auth_wep_key[i];
30746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			params.wep_key_len[i] = drv->auth_wep_key_len[i];
30751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
30768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
30778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->retry_auth = 1;
30796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return wpa_driver_nl80211_authenticate(bss, &params);
30808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
30818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
30846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					 const void *data, size_t len,
30856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					 int encrypt, int noack,
30866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					 unsigned int freq, int no_cck,
30876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					 int offchanok, unsigned int wait_time)
30888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
30896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
30906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	u64 cookie;
30916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int res;
30928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (freq == 0 && drv->nlmode == NL80211_IFTYPE_ADHOC) {
30946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		freq = nl80211_get_assoc_freq(drv);
30956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
30966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: send_frame - Use assoc_freq=%u for IBSS",
30976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   freq);
30986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
30996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (freq == 0) {
31006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: send_frame - Use bss->freq=%u",
31016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   bss->freq);
31026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		freq = bss->freq;
31038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
31048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->use_monitor) {
31066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor",
31076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   freq, bss->freq);
31086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return nl80211_send_monitor(drv, data, len, encrypt, noack);
31096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
31108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: send_frame -> send_frame_cmd");
31126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	res = nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
31136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				     &cookie, no_cck, noack, offchanok);
31146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (res == 0 && !noack) {
31156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		const struct ieee80211_mgmt *mgmt;
31166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		u16 fc;
31178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		mgmt = (const struct ieee80211_mgmt *) data;
31196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		fc = le_to_host16(mgmt->frame_control);
31206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
31216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_ACTION) {
31226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_MSGDUMP,
31236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "nl80211: Update send_action_cookie from 0x%llx to 0x%llx",
31246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   (long long unsigned int)
31256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   drv->send_action_cookie,
31266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   (long long unsigned int) cookie);
31276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			drv->send_action_cookie = cookie;
31286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
31296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
31308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return res;
31321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
31338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
31356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
31366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					size_t data_len, int noack,
31376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					unsigned int freq, int no_cck,
31386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					int offchanok,
31396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					unsigned int wait_time)
31401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
31416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
31426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct ieee80211_mgmt *mgmt;
31436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int encrypt = 1;
31446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	u16 fc;
31458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	mgmt = (struct ieee80211_mgmt *) data;
31476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	fc = le_to_host16(mgmt->frame_control);
31486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da= " MACSTR
31496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   " noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u fc=0x%x (%s) nlmode=%d",
31506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   MAC2STR(mgmt->da), noack, freq, no_cck, offchanok, wait_time,
31516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   fc, fc2str(fc), drv->nlmode);
31528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if ((is_sta_interface(drv->nlmode) ||
31546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
31556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
31566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
31576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/*
31586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * The use of last_mgmt_freq is a bit of a hack,
31596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * but it works due to the single-threaded nature
31606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * of wpa_supplicant.
31616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 */
31626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (freq == 0) {
31636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Use last_mgmt_freq=%d",
31646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   drv->last_mgmt_freq);
31656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			freq = drv->last_mgmt_freq;
31666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
31676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return nl80211_send_frame_cmd(bss, freq, 0,
31686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					      data, data_len, NULL, 1, noack,
31696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					      1);
31708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
31718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
31736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (freq == 0) {
31746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Use bss->freq=%d",
31756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   bss->freq);
31766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			freq = bss->freq;
31776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
31786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return nl80211_send_frame_cmd(bss, freq,
31796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					      (int) freq == bss->freq ? 0 :
31806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					      wait_time,
31816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					      data, data_len,
31826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					      &drv->send_action_cookie,
31836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					      no_cck, noack, offchanok);
31848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
31858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
31876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
31886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/*
31896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * Only one of the authentication frame types is encrypted.
31906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * In order for static WEP encryption to work properly (i.e.,
31916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * to not encrypt the frame), we need to tell mac80211 about
31926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * the frames that must not be encrypted.
31936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 */
31946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
31956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction);
31966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
31976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			encrypt = 0;
3198fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
3199fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
32006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame");
32016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
32026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					     noack, freq, no_cck, offchanok,
32036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					     wait_time);
32048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
32058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3207ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtstatic int nl80211_put_basic_rates(struct nl_msg *msg, const int *basic_rates)
3208ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt{
3209ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	u8 rates[NL80211_MAX_SUPP_RATES];
3210ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	u8 rates_len = 0;
3211ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	int i;
3212ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
3213ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (!basic_rates)
3214ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return 0;
3215ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
3216ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++)
3217ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		rates[rates_len++] = basic_rates[i] / 5;
3218ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
3219ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	return nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
3220ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt}
3221ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
3222ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
32236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
32246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   int slot, int ht_opmode, int ap_isolate,
3225ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   const int *basic_rates)
32261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
32276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
32286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
32291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
32306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_BSS)) ||
32316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (cts >= 0 &&
32326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_u8(msg, NL80211_ATTR_BSS_CTS_PROT, cts)) ||
32336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (preamble >= 0 &&
32346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble)) ||
32356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (slot >= 0 &&
32366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot)) ||
32376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (ht_opmode >= 0 &&
32386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_u16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode)) ||
32396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (ap_isolate >= 0 &&
3240ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	     nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate)) ||
3241ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	    nl80211_put_basic_rates(msg, basic_rates)) {
3242ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		nlmsg_free(msg);
3243ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return -ENOBUFS;
32448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
32456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
32466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
32478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
32488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_nl80211_set_acl(void *priv,
32516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				      struct hostapd_acl_params *params)
32521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
32536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
32546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
32556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
32566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *acl;
32576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	unsigned int i;
32586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
32591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
32606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(drv->capa.max_acl_mac_addrs))
32616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOTSUP;
32621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
32636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->num_mac_acl > drv->capa.max_acl_mac_addrs)
32646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOTSUP;
32651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
32666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)",
32676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   params->acl_policy ? "Accept" : "Deny", params->num_mac_acl);
32681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
32696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MAC_ACL)) ||
32706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ?
32716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			NL80211_ACL_POLICY_DENY_UNLESS_LISTED :
32726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED) ||
32736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (acl = nla_nest_start(msg, NL80211_ATTR_MAC_ADDRS)) == NULL) {
32746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
32756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOMEM;
32766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
32771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
32786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	for (i = 0; i < params->num_mac_acl; i++) {
32796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, i + 1, ETH_ALEN, params->mac_acl[i].addr)) {
32806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			nlmsg_free(msg);
32816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -ENOMEM;
32821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
32831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
32841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
32856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nla_nest_end(msg, acl);
32861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
32876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
32886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret) {
32896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)",
32906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   ret, strerror(-ret));
32916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
32926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
32936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
32941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
32951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
32961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3297ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtstatic int nl80211_put_beacon_int(struct nl_msg *msg, int beacon_int)
3298ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt{
3299ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (beacon_int > 0) {
3300ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * beacon_int=%d", beacon_int);
3301ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
3302ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				   beacon_int);
3303ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
3304ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
3305ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	return 0;
3306ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt}
3307ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
3308ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
33096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_nl80211_set_ap(void *priv,
33106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				     struct wpa_driver_ap_params *params)
33111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
33126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
33136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
33146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
33156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	u8 cmd = NL80211_CMD_NEW_BEACON;
33166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
33176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int beacon_set;
33186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int num_suites;
33196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int smps_mode;
33206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	u32 suites[10], suite;
33216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	u32 ver;
33221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
33237f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	beacon_set = params->reenable ? 0 : bss->beacon_set;
33248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
33268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   beacon_set);
33278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (beacon_set)
33288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cmd = NL80211_CMD_SET_BEACON;
33298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33300ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "nl80211: Beacon head",
33310ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		    params->head, params->head_len);
33320ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "nl80211: Beacon tail",
33330ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		    params->tail, params->tail_len);
33346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", bss->ifindex);
33350ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int);
33360ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
33370ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid",
33380ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt			  params->ssid, params->ssid_len);
33396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
33406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_BEACON_HEAD, params->head_len,
33416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    params->head) ||
33426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
33436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    params->tail) ||
3344ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	    nl80211_put_beacon_int(msg, params->beacon_int) ||
33456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period) ||
33466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
33476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
33480ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	if (params->proberesp && params->proberesp_len) {
33490ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "nl80211: proberesp (offload)",
33500ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt			    params->proberesp, params->proberesp_len);
33516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
33526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    params->proberesp))
33536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
33540ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	}
33551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	switch (params->hide_ssid) {
33561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NO_SSID_HIDING:
33570ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: hidden SSID not in use");
33586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
33596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				NL80211_HIDDEN_SSID_NOT_IN_USE))
33606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
33611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
33621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case HIDDEN_SSID_ZERO_LEN:
33630ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero len");
33646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
33656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				NL80211_HIDDEN_SSID_ZERO_LEN))
33666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
33671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
33681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case HIDDEN_SSID_ZERO_CONTENTS:
33690ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero contents");
33706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
33716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				NL80211_HIDDEN_SSID_ZERO_CONTENTS))
33726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
33731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
33741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
33750ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: privacy=%d", params->privacy);
33766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->privacy &&
33776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_flag(msg, NL80211_ATTR_PRIVACY))
33786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
33790ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: auth_algs=0x%x", params->auth_algs);
33801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
33811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
33821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		/* Leave out the attribute */
33836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else if (params->auth_algs & WPA_AUTH_ALG_SHARED) {
33846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE,
33856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				NL80211_AUTHTYPE_SHARED_KEY))
33866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
33876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else {
33886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE,
33896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				NL80211_AUTHTYPE_OPEN_SYSTEM))
33906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
33916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
33921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
33930ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: wpa_version=0x%x", params->wpa_version);
33941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ver = 0;
33951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->wpa_version & WPA_PROTO_WPA)
33961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		ver |= NL80211_WPA_VERSION_1;
33971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->wpa_version & WPA_PROTO_RSN)
33981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		ver |= NL80211_WPA_VERSION_2;
33996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ver &&
34006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
34016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
34021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
34030ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
34040ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		   params->key_mgmt_suites);
34051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	num_suites = 0;
34061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
34071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		suites[num_suites++] = WLAN_AKM_SUITE_8021X;
34081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK)
34091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		suites[num_suites++] = WLAN_AKM_SUITE_PSK;
34106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (num_suites &&
34116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
34126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    suites))
34136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
34141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
34156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
34166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40) &&
34176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))
34186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
34191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
34200ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
34210ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		   params->pairwise_ciphers);
3422fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	num_suites = wpa_cipher_to_cipher_suites(params->pairwise_ciphers,
3423fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt						 suites, ARRAY_SIZE(suites));
34246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (num_suites &&
34256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
34266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    num_suites * sizeof(u32), suites))
34276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
34281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
34290ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x",
34300ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		   params->group_cipher);
3431fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	suite = wpa_cipher_to_cipher_suite(params->group_cipher);
34326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (suite &&
34336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite))
34346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
34356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
34366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	switch (params->smps_mode) {
34376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case HT_CAP_INFO_SMPS_DYNAMIC:
34386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - dynamic");
34396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		smps_mode = NL80211_SMPS_DYNAMIC;
34406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		break;
34416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case HT_CAP_INFO_SMPS_STATIC:
34426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - static");
34436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		smps_mode = NL80211_SMPS_STATIC;
34446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		break;
34456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	default:
34466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/* invalid - fallback to smps off */
34476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case HT_CAP_INFO_SMPS_DISABLED:
34486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - off");
34496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		smps_mode = NL80211_SMPS_OFF;
34506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		break;
34516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
34526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_put_u32(msg, NL80211_ATTR_SMPS_MODE, smps_mode))
34536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
34541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
34551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->beacon_ies) {
34560ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
34570ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt				params->beacon_ies);
34586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_IE,
34596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    wpabuf_len(params->beacon_ies),
34606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    wpabuf_head(params->beacon_ies)))
34616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
34621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
34631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->proberesp_ies) {
34640ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		wpa_hexdump_buf(MSG_DEBUG, "nl80211: proberesp_ies",
34650ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt				params->proberesp_ies);
34666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_IE_PROBE_RESP,
34676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    wpabuf_len(params->proberesp_ies),
34686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    wpabuf_head(params->proberesp_ies)))
34696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
34701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
34711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->assocresp_ies) {
34720ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		wpa_hexdump_buf(MSG_DEBUG, "nl80211: assocresp_ies",
34730ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt				params->assocresp_ies);
34746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_IE_ASSOC_RESP,
34756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    wpabuf_len(params->assocresp_ies),
34766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    wpabuf_head(params->assocresp_ies)))
34776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
34781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
34798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
348004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)  {
34810ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: ap_max_inactivity=%d",
34820ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt			   params->ap_max_inactivity);
34836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
34846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				params->ap_max_inactivity))
34856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
348604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
348704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
34887f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt#ifdef CONFIG_P2P
34897f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	if (params->p2p_go_ctwindow > 0) {
34907f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		if (drv->p2p_go_ctwindow_supported) {
34917f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: P2P GO ctwindow=%d",
34927f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt				   params->p2p_go_ctwindow);
34937f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt			if (nla_put_u8(msg, NL80211_ATTR_P2P_CTWINDOW,
34947f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt				       params->p2p_go_ctwindow))
34957f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt				goto fail;
34967f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		} else {
34977f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt			wpa_printf(MSG_INFO,
34987f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt				   "nl80211: Driver does not support CTWindow configuration - ignore this parameter");
34997f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		}
35007f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	}
35017f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt#endif /* CONFIG_P2P */
35027f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
35038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
35048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
35058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
35068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ret, strerror(-ret));
35078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
35088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->beacon_set = 1;
35091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_set_bss(bss, params->cts_protect, params->preamble,
35101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				params->short_slot_time, params->ht_opmode,
35111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				params->isolate, params->basic_rates);
35127832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt		if (beacon_set && params->freq &&
35137832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt		    params->freq->bandwidth != bss->bandwidth) {
35147832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt			wpa_printf(MSG_DEBUG,
35157832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt				   "nl80211: Update BSS %s bandwidth: %d -> %d",
35167832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt				   bss->ifname, bss->bandwidth,
35177832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt				   params->freq->bandwidth);
35187832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt			ret = nl80211_set_channel(bss, params->freq, 1);
35197832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt			if (ret) {
35207832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt				wpa_printf(MSG_DEBUG,
35217832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt					   "nl80211: Frequency set failed: %d (%s)",
35227832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt					   ret, strerror(-ret));
35237832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt			} else {
35247832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt				wpa_printf(MSG_DEBUG,
35257832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt					   "nl80211: Frequency set succeeded for ht2040 coex");
35267832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt				bss->bandwidth = params->freq->bandwidth;
35277832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt			}
35287832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt		} else if (!beacon_set) {
35297832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt			/*
35307832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt			 * cfg80211 updates the driver on frequence change in AP
35317832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt			 * mode only at the point when beaconing is started, so
35327832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt			 * set the initial value here.
35337832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt			 */
35347832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt			bss->bandwidth = params->freq->bandwidth;
35357832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt		}
35368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
35378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
35386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
35391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
35408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
35418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
35428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3544e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidtstatic int nl80211_put_freq_params(struct nl_msg *msg,
35456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   const struct hostapd_freq_params *freq)
35468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3547ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	wpa_printf(MSG_DEBUG, "  * freq=%d", freq->freq);
35486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
35496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
35506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3551ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	wpa_printf(MSG_DEBUG, "  * vht_enabled=%d", freq->vht_enabled);
3552ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	wpa_printf(MSG_DEBUG, "  * ht_enabled=%d", freq->ht_enabled);
3553ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
3554a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (freq->vht_enabled) {
35556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		enum nl80211_chan_width cw;
35566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3557ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * bandwidth=%d", freq->bandwidth);
3558a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		switch (freq->bandwidth) {
3559a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		case 20:
35606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			cw = NL80211_CHAN_WIDTH_20;
3561a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			break;
3562a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		case 40:
35636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			cw = NL80211_CHAN_WIDTH_40;
3564a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			break;
3565a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		case 80:
3566a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			if (freq->center_freq2)
35676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				cw = NL80211_CHAN_WIDTH_80P80;
3568a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			else
35696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				cw = NL80211_CHAN_WIDTH_80;
3570a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			break;
3571a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		case 160:
35726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			cw = NL80211_CHAN_WIDTH_160;
3573a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			break;
3574a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		default:
3575e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt			return -EINVAL;
3576a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		}
35776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3578ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * channel_width=%d", cw);
3579ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * center_freq1=%d",
3580ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   freq->center_freq1);
3581ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * center_freq2=%d",
3582ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   freq->center_freq2);
35836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, cw) ||
35846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1,
35856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				freq->center_freq1) ||
35866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    (freq->center_freq2 &&
35876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		     nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2,
35886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				 freq->center_freq2)))
35896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -ENOBUFS;
3590a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	} else if (freq->ht_enabled) {
35916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		enum nl80211_channel_type ct;
35926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3593ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * sec_channel_offset=%d",
3594ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   freq->sec_channel_offset);
3595a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		switch (freq->sec_channel_offset) {
35968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case -1:
35976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			ct = NL80211_CHAN_HT40MINUS;
35988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
35998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case 1:
36006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			ct = NL80211_CHAN_HT40PLUS;
36018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
36028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
36036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			ct = NL80211_CHAN_HT20;
36048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
36058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
36066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
3607ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * channel_type=%d", ct);
36086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
36096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -ENOBUFS;
36108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3611e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt	return 0;
3612e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt}
3613e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
3614e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
36157832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidtstatic int nl80211_set_channel(struct i802_bss *bss,
36167832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt			       struct hostapd_freq_params *freq, int set_chan)
3617e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt{
3618e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
3619e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt	struct nl_msg *msg;
3620e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt	int ret;
3621e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
3622e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt	wpa_printf(MSG_DEBUG,
3623e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt		   "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
3624e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt		   freq->freq, freq->ht_enabled, freq->vht_enabled,
3625e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt		   freq->bandwidth, freq->center_freq1, freq->center_freq2);
3626e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
36276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_drv_msg(drv, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
36286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			      NL80211_CMD_SET_WIPHY);
36296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg || nl80211_put_freq_params(msg, freq) < 0) {
36306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
36316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
36326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
36338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
36351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ret == 0) {
3636a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		bss->freq = freq->freq;
36378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
36381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
36398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
3640a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		   "%d (%s)", freq->freq, ret, strerror(-ret));
36418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
36428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
36438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic u32 sta_flags_nl80211(int flags)
36468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
36471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u32 f = 0;
36488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (flags & WPA_STA_AUTHORIZED)
36501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
36511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (flags & WPA_STA_WMM)
36521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		f |= BIT(NL80211_STA_FLAG_WME);
36531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (flags & WPA_STA_SHORT_PREAMBLE)
36541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
36551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (flags & WPA_STA_MFP)
36561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		f |= BIT(NL80211_STA_FLAG_MFP);
36571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (flags & WPA_STA_TDLS_PEER)
36581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
36596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (flags & WPA_STA_AUTHENTICATED)
36606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		f |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
36611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
36621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return f;
36631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
36641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
36651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
36666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_MESH
36676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic u32 sta_plink_state_nl80211(enum mesh_plink_state state)
36686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
36696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	switch (state) {
36706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case PLINK_LISTEN:
36716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL80211_PLINK_LISTEN;
36726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case PLINK_OPEN_SENT:
36736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL80211_PLINK_OPN_SNT;
36746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case PLINK_OPEN_RCVD:
36756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL80211_PLINK_OPN_RCVD;
36766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case PLINK_CNF_RCVD:
36776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL80211_PLINK_CNF_RCVD;
36786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case PLINK_ESTAB:
36796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL80211_PLINK_ESTAB;
36806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case PLINK_HOLDING:
36816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL80211_PLINK_HOLDING;
36826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case PLINK_BLOCKED:
36836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL80211_PLINK_BLOCKED;
36846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	default:
36856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Invalid mesh plink state %d",
36866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   state);
36876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
36886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return -1;
36896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
36906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_MESH */
36916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
36926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
36931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int wpa_driver_nl80211_sta_add(void *priv,
36941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				      struct hostapd_sta_add_params *params)
36951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
36961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct i802_bss *bss = priv;
36971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
36988da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	struct nl_msg *msg;
36991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl80211_sta_flag_update upd;
37001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int ret = -ENOBUFS;
37011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
37021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if ((params->flags & WPA_STA_TDLS_PEER) &&
37031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
37041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -EOPNOTSUPP;
37051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3706f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR,
3707f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		   params->set ? "Set" : "Add", MAC2STR(params->addr));
37086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_bss_msg(bss, 0, params->set ? NL80211_CMD_SET_STATION :
37096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			      NL80211_CMD_NEW_STATION);
37106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg || nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr))
37116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
37126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
37136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!params->set || (params->flags & WPA_STA_TDLS_PEER)) {
37146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "  * supported rates",
37156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    params->supp_rates, params->supp_rates_len);
37166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * capability=0x%x",
37176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   params->capability);
37186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_RATES,
37196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    params->supp_rates_len, params->supp_rates) ||
37206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    nla_put_u16(msg, NL80211_ATTR_STA_CAPABILITY,
37216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				params->capability))
37226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
37236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
37246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (params->ht_capabilities) {
37256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_hexdump(MSG_DEBUG, "  * ht_capabilities",
37266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    (u8 *) params->ht_capabilities,
37276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    sizeof(*params->ht_capabilities));
37286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY,
37296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    sizeof(*params->ht_capabilities),
37306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    params->ht_capabilities))
37316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
37326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
37336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
37346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (params->vht_capabilities) {
37356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_hexdump(MSG_DEBUG, "  * vht_capabilities",
37366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    (u8 *) params->vht_capabilities,
37376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    sizeof(*params->vht_capabilities));
37386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY,
37396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    sizeof(*params->vht_capabilities),
37406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    params->vht_capabilities))
37416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
37426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
37436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
37446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (params->ext_capab) {
37456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_hexdump(MSG_DEBUG, "  * ext_capab",
37466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    params->ext_capab, params->ext_capab_len);
37476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (nla_put(msg, NL80211_ATTR_STA_EXT_CAPABILITY,
37486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    params->ext_capab_len, params->ext_capab))
37496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
37506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
37516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
37521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!params->set) {
375351b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt		if (params->aid) {
375451b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt			wpa_printf(MSG_DEBUG, "  * aid=%u", params->aid);
37556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (nla_put_u16(msg, NL80211_ATTR_STA_AID, params->aid))
37566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
375751b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt		} else {
375851b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt			/*
375951b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt			 * cfg80211 validates that AID is non-zero, so we have
376051b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt			 * to make this a non-zero value for the TDLS case where
376151b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt			 * a dummy STA entry is used for now.
376251b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt			 */
376351b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt			wpa_printf(MSG_DEBUG, "  * aid=1 (TDLS workaround)");
37646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (nla_put_u16(msg, NL80211_ATTR_STA_AID, 1))
37656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				goto fail;
376651b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt		}
3767f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * listen_interval=%u",
3768f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			   params->listen_interval);
37696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
37706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				params->listen_interval))
37716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
37728bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	} else if (params->aid && (params->flags & WPA_STA_TDLS_PEER)) {
37738bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * peer_aid=%u", params->aid);
37746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u16(msg, NL80211_ATTR_PEER_AID, params->aid))
37756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
3776a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
3777a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
3778bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt	if (params->vht_opmode_enabled) {
3779bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * opmode=%u", params->vht_opmode);
37806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u8(msg, NL80211_ATTR_OPMODE_NOTIF,
37816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			       params->vht_opmode))
37826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
3783f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	}
3784f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
3785344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt	if (params->supp_channels) {
3786344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		wpa_hexdump(MSG_DEBUG, "  * supported channels",
3787344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt			    params->supp_channels, params->supp_channels_len);
37886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_CHANNELS,
37896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    params->supp_channels_len, params->supp_channels))
37906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
3791344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt	}
3792344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt
3793344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt	if (params->supp_oper_classes) {
3794344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		wpa_hexdump(MSG_DEBUG, "  * supported operating classes",
3795344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt			    params->supp_oper_classes,
3796344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt			    params->supp_oper_classes_len);
37976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
37986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    params->supp_oper_classes_len,
37996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    params->supp_oper_classes))
38006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
3801344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt	}
3802344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt
38031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memset(&upd, 0, sizeof(upd));
38046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	upd.set = sta_flags_nl80211(params->flags);
38056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	upd.mask = upd.set | sta_flags_nl80211(params->flags_mask);
3806f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	wpa_printf(MSG_DEBUG, "  * flags set=0x%x mask=0x%x",
3807f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		   upd.set, upd.mask);
38086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
38096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
38106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
38116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_MESH
38126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->plink_state &&
38136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u8(msg, NL80211_ATTR_STA_PLINK_STATE,
38146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		       sta_plink_state_nl80211(params->plink_state)))
38156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
38166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_MESH */
38171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
38181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->flags & WPA_STA_WMM) {
38198da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
38208da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt
3821f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * qosinfo=0x%x", params->qosinfo);
38226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (!wme ||
38236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES,
38246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			       params->qosinfo & WMM_QOSINFO_STA_AC_MASK) ||
38256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    nla_put_u8(msg, NL80211_STA_WME_MAX_SP,
38266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			       (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
38276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			       WMM_QOSINFO_STA_SP_MASK))
38286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
38298da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		nla_nest_end(msg, wme);
38301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
38311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
38328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
38331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
38348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret)
38351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
38361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "result: %d (%s)", params->set ? "SET" : "NEW", ret,
38371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   strerror(-ret));
38388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == -EEXIST)
38398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = 0;
38406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
38411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
38428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
38438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
38448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3846661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidtstatic void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr)
3847661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt{
3848661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt#ifdef CONFIG_LIBNL3_ROUTE
3849661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
3850661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	struct rtnl_neigh *rn;
3851661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	struct nl_addr *nl_addr;
3852661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	int err;
3853661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
3854661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	rn = rtnl_neigh_alloc();
3855661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	if (!rn)
3856661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		return;
3857661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
3858661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	rtnl_neigh_set_family(rn, AF_BRIDGE);
3859661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	rtnl_neigh_set_ifindex(rn, bss->ifindex);
3860661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	nl_addr = nl_addr_build(AF_BRIDGE, (void *) addr, ETH_ALEN);
3861661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	if (!nl_addr) {
3862661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		rtnl_neigh_put(rn);
3863661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		return;
3864661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	}
3865661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	rtnl_neigh_set_lladdr(rn, nl_addr);
3866661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
3867661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	err = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
3868661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	if (err < 0) {
3869661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry delete for "
3870661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			   MACSTR " ifindex=%d failed: %s", MAC2STR(addr),
3871661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			   bss->ifindex, nl_geterror(err));
3872661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	} else {
3873661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: deleted bridge FDB entry for "
3874661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			   MACSTR, MAC2STR(addr));
3875661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	}
3876661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
3877661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	nl_addr_put(nl_addr);
3878661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	rtnl_neigh_put(rn);
3879661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt#endif /* CONFIG_LIBNL3_ROUTE */
3880661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt}
3881661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
3882661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
38836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr,
38846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					 int deauth, u16 reason_code)
38858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
38868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
38878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
38888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
38898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION)) ||
38916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
38926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (deauth == 0 &&
38936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
38946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			WLAN_FC_STYPE_DISASSOC)) ||
38956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (deauth == 1 &&
38966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
38976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			WLAN_FC_STYPE_DEAUTH)) ||
38986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (reason_code &&
38996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code))) {
39006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
39016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
39026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
39038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
3905b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR
3906b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		   " --> %d (%s)",
3907b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		   bss->ifname, MAC2STR(addr), ret, strerror(-ret));
3908661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
3909661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	if (drv->rtnl_sk)
3910661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		rtnl_neigh_delete_fdb_entry(bss, addr);
3911661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
39128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == -ENOENT)
39138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
39148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
39158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
39168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtvoid nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx)
39198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
39208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
392176cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt	struct wpa_driver_nl80211_data *drv2;
39228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
39248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* stop listening for EAPOL on this interface */
392676cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt	dl_list_for_each(drv2, &drv->global->interfaces,
392776cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt			 struct wpa_driver_nl80211_data, list)
392876cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt		del_ifidx(drv2, ifidx);
39298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_ifindex_msg(drv, ifidx, 0, NL80211_CMD_DEL_INTERFACE);
39318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
39328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
39338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
39348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
39358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic const char * nl80211_iftype_str(enum nl80211_iftype mode)
39381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
39391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	switch (mode) {
39401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_IFTYPE_ADHOC:
39411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return "ADHOC";
39421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_IFTYPE_STATION:
39431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return "STATION";
39441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_IFTYPE_AP:
39451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return "AP";
3946f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt	case NL80211_IFTYPE_AP_VLAN:
3947f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt		return "AP_VLAN";
3948f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt	case NL80211_IFTYPE_WDS:
3949f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt		return "WDS";
39501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_IFTYPE_MONITOR:
39511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return "MONITOR";
3952f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt	case NL80211_IFTYPE_MESH_POINT:
3953f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt		return "MESH_POINT";
39541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_IFTYPE_P2P_CLIENT:
39551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return "P2P_CLIENT";
39561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_IFTYPE_P2P_GO:
39571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return "P2P_GO";
395834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case NL80211_IFTYPE_P2P_DEVICE:
395934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return "P2P_DEVICE";
39601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	default:
39611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return "unknown";
39621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
39631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
39641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
39651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
39668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
39678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     const char *ifname,
39688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     enum nl80211_iftype iftype,
396934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				     const u8 *addr, int wds,
397034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				     int (*handler)(struct nl_msg *, void *),
397134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				     void *arg)
39728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
39738da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	struct nl_msg *msg;
39748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifidx;
39758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -ENOBUFS;
39768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)",
39781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   iftype, nl80211_iftype_str(iftype));
39791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
39806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_NEW_INTERFACE);
39816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg ||
39826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_string(msg, NL80211_ATTR_IFNAME, ifname) ||
39836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_IFTYPE, iftype))
39846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
39858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (iftype == NL80211_IFTYPE_MONITOR) {
39878da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		struct nlattr *flags;
39888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39898da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
39906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (!flags ||
39916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    nla_put_flag(msg, NL80211_MNTR_FLAG_COOK_FRAMES))
39926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
39938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39948da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		nla_nest_end(msg, flags);
39958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (wds) {
39966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u8(msg, NL80211_ATTR_4ADDR, wds))
39976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
39988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
39998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4000b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt	/*
4001b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt	 * Tell cfg80211 that the interface belongs to the socket that created
4002b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt	 * it, and the interface should be deleted when the socket is closed.
4003b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt	 */
40046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
40056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
4006b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt
400734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, handler, arg);
40081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
40098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
40106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	fail:
40111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nlmsg_free(msg);
40128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
40138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ifname, ret, strerror(-ret));
40148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ret;
40158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
40168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
401734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (iftype == NL80211_IFTYPE_P2P_DEVICE)
401834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return 0;
401934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
40208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ifidx = if_nametoindex(ifname);
40218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
40228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   ifname, ifidx);
40238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ifidx <= 0)
40258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
40268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
402776cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt	/*
402876cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt	 * Some virtual interfaces need to process EAPOL packets and events on
402976cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt	 * the parent interface. This is used mainly with hostapd.
403076cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt	 */
403176cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt	if (drv->hostapd ||
403276cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt	    iftype == NL80211_IFTYPE_AP_VLAN ||
403376cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt	    iftype == NL80211_IFTYPE_WDS ||
403476cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt	    iftype == NL80211_IFTYPE_MONITOR) {
403576cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt		/* start listening for EAPOL on this interface */
403676cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt		add_ifidx(drv, ifidx);
403776cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt	}
40388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (addr && iftype != NL80211_IFTYPE_MONITOR &&
40401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) {
40418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_remove_iface(drv, ifidx);
40428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
40438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
40448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ifidx;
40468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
40478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
40506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 const char *ifname, enum nl80211_iftype iftype,
40516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 const u8 *addr, int wds,
40526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 int (*handler)(struct nl_msg *, void *),
40536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 void *arg, int use_existing)
40548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
40558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
40568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
405734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds, handler,
405834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					arg);
40598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* if error occurred and interface exists already */
40618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == -ENFILE && if_nametoindex(ifname)) {
4062cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (use_existing) {
4063cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Continue using existing interface %s",
4064cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				   ifname);
4065df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			if (addr && iftype != NL80211_IFTYPE_MONITOR &&
4066df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			    linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
4067df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt					       addr) < 0 &&
4068df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			    (linux_set_iface_flags(drv->global->ioctl_sock,
4069df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt						   ifname, 0) < 0 ||
4070df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			     linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
4071df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt						addr) < 0 ||
4072df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			     linux_set_iface_flags(drv->global->ioctl_sock,
4073df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt						   ifname, 1) < 0))
4074df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt					return -1;
4075cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			return -ENFILE;
4076cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		}
40778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
40788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Try to remove the interface that was already there. */
40808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_remove_iface(drv, if_nametoindex(ifname));
40818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Try to create the interface again */
40838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
408434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt						wds, handler, arg);
40858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
40868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret >= 0 && is_p2p_net_interface(iftype)) {
40886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
40896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Interface %s created for P2P - disable 11b rates",
40906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   ifname);
40918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_disable_11b_rates(drv, ret, 1);
40928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
40938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
40958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
40968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_setup_ap(struct i802_bss *bss)
40991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
41001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
41011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4102cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Setup AP(%s) - device_ap_sme=%d use_monitor=%d",
4103cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		   bss->ifname, drv->device_ap_sme, drv->use_monitor);
41041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
41051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/*
41061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * Disable Probe Request reporting unless we need it in this way for
41071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * devices that include the AP SME, in the other case (unless using
41081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * monitor iface) we'll get it through the nl_mgmt socket instead.
41091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 */
41101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!drv->device_ap_sme)
41111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_driver_nl80211_probe_req_report(bss, 0);
41121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
41131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!drv->device_ap_sme && !drv->use_monitor)
41141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (nl80211_mgmt_subscribe_ap(bss))
41151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return -1;
41161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
41171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->device_ap_sme && !drv->use_monitor)
41181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
41191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return -1;
41201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
41211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!drv->device_ap_sme && drv->use_monitor &&
41221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    nl80211_create_monitor_interface(drv) &&
41231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    !drv->device_ap_sme)
412404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return -1;
412504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
41261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->device_ap_sme &&
41271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
41281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
41291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "Probe Request frame reporting in AP mode");
41301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		/* Try to survive without this */
41311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
41321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
41331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
41341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
41351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
41361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
41371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nl80211_teardown_ap(struct i802_bss *bss)
41381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
41391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
41401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4141cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Teardown AP(%s) - device_ap_sme=%d use_monitor=%d",
4142cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		   bss->ifname, drv->device_ap_sme, drv->use_monitor);
41431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->device_ap_sme) {
41441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_driver_nl80211_probe_req_report(bss, 0);
41451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (!drv->use_monitor)
41461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			nl80211_mgmt_unsubscribe(bss, "AP teardown (dev SME)");
41471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else if (drv->use_monitor)
41481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_remove_monitor_interface(drv);
41491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	else
41501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_mgmt_unsubscribe(bss, "AP teardown");
41511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
41521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	bss->beacon_set = 0;
41531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
41541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
41551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
41561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_send_eapol_data(struct i802_bss *bss,
41571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   const u8 *addr, const u8 *data,
41581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   size_t data_len)
41591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
41601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct sockaddr_ll ll;
41611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int ret;
41621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
41631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (bss->drv->eapol_tx_sock < 0) {
41641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: No socket to send EAPOL");
41651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
41661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
41671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
41681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memset(&ll, 0, sizeof(ll));
41691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ll.sll_family = AF_PACKET;
41701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ll.sll_ifindex = bss->ifindex;
41711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ll.sll_protocol = htons(ETH_P_PAE);
41721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ll.sll_halen = ETH_ALEN;
41731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memcpy(ll.sll_addr, addr, ETH_ALEN);
41741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0,
41751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		     (struct sockaddr *) &ll, sizeof(ll));
41761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ret < 0)
41771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: EAPOL TX: %s",
41781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   strerror(errno));
41791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
41801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return ret;
41811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
41821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
41831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
41848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
41858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_hapd_send_eapol(
41878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *priv, const u8 *addr, const u8 *data,
41888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t data_len, int encrypt, const u8 *own_addr, u32 flags)
41898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
41908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
41918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
41928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee80211_hdr *hdr;
41938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len;
41948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *pos;
41958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res;
41968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int qos = flags & WPA_STA_WMM;
4197641185ebd73d9607756c87b22f6c520ab1846325Dmitry Shmidt
41981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->device_ap_sme || !drv->use_monitor)
41991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return nl80211_send_eapol_data(bss, addr, data, data_len);
42001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
42018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
42028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data_len;
42038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = os_zalloc(len);
42048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hdr == NULL) {
420568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		wpa_printf(MSG_INFO, "nl80211: Failed to allocate EAPOL buffer(len=%lu)",
420668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			   (unsigned long) len);
42078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
42088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
42098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr->frame_control =
42118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
42128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
42138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encrypt)
42148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
42158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (qos) {
42168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hdr->frame_control |=
42178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
42188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
42198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
42218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
42228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
42238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = (u8 *) (hdr + 1);
42248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (qos) {
4226aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt		/* Set highest priority in QoS header */
4227aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt		pos[0] = 7;
42288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos[1] = 0;
42298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
42308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
42318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
42338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += sizeof(rfc1042_header);
42348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE16(pos, ETH_P_PAE);
42358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += 2;
42368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(pos, data, data_len);
42378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4238c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0,
4239c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					    0, 0, 0, 0);
42408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res < 0) {
42418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
42428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "failed: %d (%s)",
42438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (unsigned long) len, errno, strerror(errno));
42448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
42458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(hdr);
42468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return res;
42488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
42498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
42528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    int total_flags,
42538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    int flags_or, int flags_and)
42548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
42558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
42568da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	struct nl_msg *msg;
42578da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	struct nlattr *flags;
42588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl80211_sta_flag_update upd;
42598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4260661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Set STA flags - ifname=%s addr=" MACSTR
4261661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		   " total_flags=0x%x flags_or=0x%x flags_and=0x%x authorized=%d",
4262661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		   bss->ifname, MAC2STR(addr), total_flags, flags_or, flags_and,
4263661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		   !!(total_flags & WPA_STA_AUTHORIZED));
4264661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
42656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
42666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
42676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
42688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
42708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
42718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * can be removed eventually.
42728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
42738da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	flags = nla_nest_start(msg, NL80211_ATTR_STA_FLAGS);
42746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!flags ||
42756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    ((total_flags & WPA_STA_AUTHORIZED) &&
42766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_flag(msg, NL80211_STA_FLAG_AUTHORIZED)) ||
42776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    ((total_flags & WPA_STA_WMM) &&
42786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_flag(msg, NL80211_STA_FLAG_WME)) ||
42796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    ((total_flags & WPA_STA_SHORT_PREAMBLE) &&
42806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_flag(msg, NL80211_STA_FLAG_SHORT_PREAMBLE)) ||
42816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    ((total_flags & WPA_STA_MFP) &&
42826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_flag(msg, NL80211_STA_FLAG_MFP)) ||
42836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    ((total_flags & WPA_STA_TDLS_PEER) &&
42846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_flag(msg, NL80211_STA_FLAG_TDLS_PEER)))
42856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
42861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
42878da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	nla_nest_end(msg, flags);
42888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&upd, 0, sizeof(upd));
42908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
42918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	upd.set = sta_flags_nl80211(flags_or);
42926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
42936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
42948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
42966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
42971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
42988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
42998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
43008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
43038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 struct wpa_driver_associate_params *params)
43048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4305a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	enum nl80211_iftype nlmode, old_mode;
43061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
43071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->p2p) {
43088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P "
43098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "group (GO)");
43101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nlmode = NL80211_IFTYPE_P2P_GO;
43111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else
43121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nlmode = NL80211_IFTYPE_AP;
43131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4314a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	old_mode = drv->nlmode;
4315cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (wpa_driver_nl80211_set_mode(drv->first_bss, nlmode)) {
4316a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		nl80211_remove_monitor_interface(drv);
4317a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return -1;
4318a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
4319a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
4320203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	if (params->freq.freq &&
4321203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	    nl80211_set_channel(drv->first_bss, &params->freq, 0)) {
4322a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		if (old_mode != nlmode)
4323cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			wpa_driver_nl80211_set_mode(drv->first_bss, old_mode);
43248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_remove_monitor_interface(drv);
43258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
43268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
43278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
43298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
43308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
43336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			      int reset_mode)
43348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
43358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
43366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
43378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_IBSS);
43398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
43408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
43418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
43428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", ret, strerror(-ret));
43436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else {
43446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
43456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Leave IBSS request sent successfully");
43468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
43478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (reset_mode &&
43496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    wpa_driver_nl80211_set_mode(drv->first_bss,
43505605286c30e1701491bd3af974ae423727750eddDmitry Shmidt					NL80211_IFTYPE_STATION)) {
43515605286c30e1701491bd3af974ae423727750eddDmitry Shmidt		wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
43525605286c30e1701491bd3af974ae423727750eddDmitry Shmidt			   "station mode");
43535605286c30e1701491bd3af974ae423727750eddDmitry Shmidt	}
43545605286c30e1701491bd3af974ae423727750eddDmitry Shmidt
43558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
43568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
43578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43592f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidtstatic int nl80211_ht_vht_overrides(struct nl_msg *msg,
43602f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				    struct wpa_driver_associate_params *params)
43612f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt{
43622f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	if (params->disable_ht && nla_put_flag(msg, NL80211_ATTR_DISABLE_HT))
43632f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		return -1;
43642f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
43652f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	if (params->htcaps && params->htcaps_mask) {
43662f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		int sz = sizeof(struct ieee80211_ht_capabilities);
43672f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "  * htcaps", params->htcaps, sz);
43682f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "  * htcaps_mask",
43692f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			    params->htcaps_mask, sz);
43702f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY, sz,
43712f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			    params->htcaps) ||
43722f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		    nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
43732f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			    params->htcaps_mask))
43742f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			return -1;
43752f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	}
43762f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
43772f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt#ifdef CONFIG_VHT_OVERRIDES
43782f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	if (params->disable_vht) {
43792f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * VHT disabled");
43802f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		if (nla_put_flag(msg, NL80211_ATTR_DISABLE_VHT))
43812f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			return -1;
43822f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	}
43832f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
43842f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	if (params->vhtcaps && params->vhtcaps_mask) {
43852f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		int sz = sizeof(struct ieee80211_vht_capabilities);
43862f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "  * vhtcaps", params->vhtcaps, sz);
43872f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "  * vhtcaps_mask",
43882f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			    params->vhtcaps_mask, sz);
43892f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY, sz,
43902f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			    params->vhtcaps) ||
43912f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		    nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
43922f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			    params->vhtcaps_mask))
43932f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			return -1;
43942f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	}
43952f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt#endif /* CONFIG_VHT_OVERRIDES */
43962f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
43972f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	return 0;
43982f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt}
43992f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
44002f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
44018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
44028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   struct wpa_driver_associate_params *params)
44038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
44048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
44058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
44068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int count = 0;
44078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
44098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44109ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	if (wpa_driver_nl80211_set_mode_ibss(drv->first_bss, &params->freq)) {
44118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
44128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "IBSS mode");
44138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
44148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
44158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtretry:
44176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_IBSS)) ||
44186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
44196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
44208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
44228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  params->ssid, params->ssid_len);
44236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
44246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
44258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(drv->ssid, params->ssid, params->ssid_len);
44268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->ssid_len = params->ssid_len;
44278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4428ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (nl80211_put_freq_params(msg, &params->freq) < 0 ||
4429ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	    nl80211_put_beacon_int(msg, params->beacon_int))
44306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
44318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = nl80211_set_conn_keys(params, msg);
44338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret)
44346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
44358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4436c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (params->bssid && params->fixed_bssid) {
4437c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * BSSID=" MACSTR,
4438c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			   MAC2STR(params->bssid));
44396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
44406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
4441c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
4442c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
44437f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	if (params->fixed_freq) {
44447f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * fixed_freq");
44457f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		if (nla_put_flag(msg, NL80211_ATTR_FREQ_FIXED))
44467f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt			goto fail;
44477f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	}
44487f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
4449fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
4450fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	    params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
4451fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	    params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
4452fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	    params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256) {
4453c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * control port");
44546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
44556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
4456c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
4457c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
44588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->wpa_ie) {
44598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_DEBUG,
44608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    "  * Extra IEs for Beacon/Probe Response frames",
44618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    params->wpa_ie, params->wpa_ie_len);
44626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len,
44636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    params->wpa_ie))
44646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
44658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
44668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44672f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	if (nl80211_ht_vht_overrides(msg, params) < 0)
44682f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		return -1;
44692f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
44708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
44718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
44728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
44738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
44748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ret, strerror(-ret));
44758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		count++;
44768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret == -EALREADY && count == 1) {
44778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
44788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "forced leave");
44796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			nl80211_leave_ibss(drv, 0);
44808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nlmsg_free(msg);
44818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto retry;
44828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
44836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else {
44846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
44856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Join IBSS request sent successfully");
44868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
44878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
44898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
44908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
44918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
44928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4494fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidtstatic int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
4495fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				  struct wpa_driver_associate_params *params,
4496fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt				  struct nl_msg *msg)
44978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
44988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->bssid) {
44998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * bssid=" MACSTR,
45008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(params->bssid));
45016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
45026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -1;
45038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4504fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
450596be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt	if (params->bssid_hint) {
450696be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * bssid_hint=" MACSTR,
450796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt			   MAC2STR(params->bssid_hint));
45086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_MAC_HINT, ETH_ALEN,
45096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    params->bssid_hint))
45106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -1;
451196be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt	}
451296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt
45139ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt	if (params->freq.freq) {
45149ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq.freq);
45156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
45166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				params->freq.freq))
45176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -1;
45189ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt		drv->assoc_freq = params->freq.freq;
4519b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	} else
4520b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		drv->assoc_freq = 0;
4521fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
452296be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt	if (params->freq_hint) {
452396be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * freq_hint=%d", params->freq_hint);
45246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_HINT,
45256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				params->freq_hint))
45266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -1;
452796be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt	}
452896be6222df414a7dde5c5b1b72df22e67b1a77fcDmitry Shmidt
452904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (params->bg_scan_period >= 0) {
453004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * bg scan period=%d",
453104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			   params->bg_scan_period);
45326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
45336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				params->bg_scan_period))
45346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -1;
453504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
4536fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
45378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->ssid) {
45388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
45398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  params->ssid, params->ssid_len);
45406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
45416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    params->ssid))
45426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -1;
45438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->ssid_len > sizeof(drv->ssid))
45446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -1;
45458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(drv->ssid, params->ssid, params->ssid_len);
45468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->ssid_len = params->ssid_len;
45478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4548fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
45498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "  * IEs", params->wpa_ie, params->wpa_ie_len);
45506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->wpa_ie &&
45516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len, params->wpa_ie))
45526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
45538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->wpa_proto) {
45551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		enum nl80211_wpa_versions ver = 0;
45568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (params->wpa_proto & WPA_PROTO_WPA)
45581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			ver |= NL80211_WPA_VERSION_1;
45591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (params->wpa_proto & WPA_PROTO_RSN)
45601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			ver |= NL80211_WPA_VERSION_2;
45618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * WPA Versions 0x%x", ver);
45636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
45646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -1;
45658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
45668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4567fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (params->pairwise_suite != WPA_CIPHER_NONE) {
4568fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		u32 cipher = wpa_cipher_to_cipher_suite(params->pairwise_suite);
4569fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * pairwise=0x%x", cipher);
45706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
45716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				cipher))
45726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -1;
45738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
45748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4575f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	if (params->group_suite == WPA_CIPHER_GTK_NOT_USED &&
4576f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	    !(drv->capa.enc & WPA_DRIVER_CAPA_ENC_GTK_NOT_USED)) {
4577f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		/*
4578f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		 * This is likely to work even though many drivers do not
4579f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		 * advertise support for operations without GTK.
4580f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		 */
4581f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * skip group cipher configuration for GTK_NOT_USED due to missing driver support advertisement");
4582f21452aea786ac056eb01f1cbba4f553bd502747Dmitry Shmidt	} else if (params->group_suite != WPA_CIPHER_NONE) {
4583fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		u32 cipher = wpa_cipher_to_cipher_suite(params->group_suite);
4584fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * group=0x%x", cipher);
45856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher))
45866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -1;
45878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
45888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4589fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
4590fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	    params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
4591fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	    params->key_mgmt_suite == WPA_KEY_MGMT_FT_IEEE8021X ||
4592fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	    params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK ||
459315907098d1f67c24bb000e593e279af173cf57d7Dmitry Shmidt	    params->key_mgmt_suite == WPA_KEY_MGMT_CCKM ||
45943c57b3f85a2d1d586b8b42014a806df23d309824Dmitry Shmidt	    params->key_mgmt_suite == WPA_KEY_MGMT_OSEN ||
45953c57b3f85a2d1d586b8b42014a806df23d309824Dmitry Shmidt	    params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
45966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
4597807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	    params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
4598807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	    params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
45998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int mgmt = WLAN_AKM_SUITE_PSK;
46008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
46018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (params->key_mgmt_suite) {
4602fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		case WPA_KEY_MGMT_CCKM:
4603d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			mgmt = WLAN_AKM_SUITE_CCKM;
4604d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			break;
4605fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		case WPA_KEY_MGMT_IEEE8021X:
46068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			mgmt = WLAN_AKM_SUITE_8021X;
46078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
4608fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		case WPA_KEY_MGMT_FT_IEEE8021X:
4609700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt			mgmt = WLAN_AKM_SUITE_FT_8021X;
4610700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt			break;
4611fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		case WPA_KEY_MGMT_FT_PSK:
4612700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt			mgmt = WLAN_AKM_SUITE_FT_PSK;
4613700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt			break;
46143c57b3f85a2d1d586b8b42014a806df23d309824Dmitry Shmidt		case WPA_KEY_MGMT_IEEE8021X_SHA256:
46153c57b3f85a2d1d586b8b42014a806df23d309824Dmitry Shmidt			mgmt = WLAN_AKM_SUITE_8021X_SHA256;
46163c57b3f85a2d1d586b8b42014a806df23d309824Dmitry Shmidt			break;
46173c57b3f85a2d1d586b8b42014a806df23d309824Dmitry Shmidt		case WPA_KEY_MGMT_PSK_SHA256:
46183c57b3f85a2d1d586b8b42014a806df23d309824Dmitry Shmidt			mgmt = WLAN_AKM_SUITE_PSK_SHA256;
46193c57b3f85a2d1d586b8b42014a806df23d309824Dmitry Shmidt			break;
462015907098d1f67c24bb000e593e279af173cf57d7Dmitry Shmidt		case WPA_KEY_MGMT_OSEN:
462115907098d1f67c24bb000e593e279af173cf57d7Dmitry Shmidt			mgmt = WLAN_AKM_SUITE_OSEN;
462215907098d1f67c24bb000e593e279af173cf57d7Dmitry Shmidt			break;
46236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
46246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			mgmt = WLAN_AKM_SUITE_8021X_SUITE_B;
46256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			break;
4626807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt		case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
4627807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt			mgmt = WLAN_AKM_SUITE_8021X_SUITE_B_192;
4628807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt			break;
4629fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		case WPA_KEY_MGMT_PSK:
46308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
46318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			mgmt = WLAN_AKM_SUITE_PSK;
46328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
46338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
463415907098d1f67c24bb000e593e279af173cf57d7Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * akm=0x%x", mgmt);
46356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, mgmt))
46366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -1;
46378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
46388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
46396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
46406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
46416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
46426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
46436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
46446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
4645fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
46466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->rrm_used) {
46476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		u32 drv_rrm_flags = drv->capa.rrm_flags;
46486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (!(drv_rrm_flags &
46496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		      WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) ||
46506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    !(drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET) ||
46516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    nla_put_flag(msg, NL80211_ATTR_USE_RRM))
46526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -1;
46536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
4654a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
46552f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	if (nl80211_ht_vht_overrides(msg, params) < 0)
46566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
4657c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
4658fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (params->p2p)
4659fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * P2P group");
4660fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
4661fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	return 0;
4662fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt}
4663fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
4664fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
4665fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidtstatic int wpa_driver_nl80211_try_connect(
4666fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	struct wpa_driver_nl80211_data *drv,
4667fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	struct wpa_driver_associate_params *params)
4668fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt{
4669fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	struct nl_msg *msg;
4670fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	enum nl80211_auth_type type;
4671fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	int ret;
4672fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	int algs;
4673fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
46746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->req_key_mgmt_offload && params->psk &&
46756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
46766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
46776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
46786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Key management set PSK");
46796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = issue_key_mgmt_set_key(drv, params->psk, 32);
46806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (ret)
46816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return ret;
46826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
4683fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
4684fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
46856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_CONNECT);
46866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg)
46876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
4688fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
4689fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	ret = nl80211_connect_common(drv, params, msg);
4690fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ret)
46916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
4692fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
4693fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	algs = 0;
4694fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (params->auth_alg & WPA_AUTH_ALG_OPEN)
4695fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		algs++;
4696fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (params->auth_alg & WPA_AUTH_ALG_SHARED)
4697fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		algs++;
4698fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (params->auth_alg & WPA_AUTH_ALG_LEAP)
4699fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		algs++;
4700fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (algs > 1) {
4701fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * Leave out Auth Type for automatic "
4702fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt			   "selection");
4703fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		goto skip_auth_type;
4704fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
4705fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
4706fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (params->auth_alg & WPA_AUTH_ALG_OPEN)
4707fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		type = NL80211_AUTHTYPE_OPEN_SYSTEM;
4708fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
4709fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		type = NL80211_AUTHTYPE_SHARED_KEY;
4710fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
4711fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		type = NL80211_AUTHTYPE_NETWORK_EAP;
4712fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	else if (params->auth_alg & WPA_AUTH_ALG_FT)
4713fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		type = NL80211_AUTHTYPE_FT;
4714fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	else
47156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
4716fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
4717fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	wpa_printf(MSG_DEBUG, "  * Auth Type %d", type);
47186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
47196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
4720fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
4721fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidtskip_auth_type:
47228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = nl80211_set_conn_keys(params, msg);
47238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret)
47246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
47258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
47278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
47288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
47298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
47308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", ret, strerror(-ret));
47316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else {
47326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
47336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Connect request send successfully");
47348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
47358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
47378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
47388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
47398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
47418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4743d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtstatic int wpa_driver_nl80211_connect(
4744d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	struct wpa_driver_nl80211_data *drv,
4745d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	struct wpa_driver_associate_params *params)
4746d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt{
4747a7c60b4c03ced564d424e4cae81b85f7112aa59bJithu Jance	int ret;
4748a7c60b4c03ced564d424e4cae81b85f7112aa59bJithu Jance
4749a7c60b4c03ced564d424e4cae81b85f7112aa59bJithu Jance	/* Store the connection attempted bssid for future use */
4750a7c60b4c03ced564d424e4cae81b85f7112aa59bJithu Jance	if (params->bssid)
4751a7c60b4c03ced564d424e4cae81b85f7112aa59bJithu Jance		os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
4752a7c60b4c03ced564d424e4cae81b85f7112aa59bJithu Jance	else
4753a7c60b4c03ced564d424e4cae81b85f7112aa59bJithu Jance		os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
4754a7c60b4c03ced564d424e4cae81b85f7112aa59bJithu Jance
4755a7c60b4c03ced564d424e4cae81b85f7112aa59bJithu Jance	ret = wpa_driver_nl80211_try_connect(drv, params);
4756d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (ret == -EALREADY) {
4757d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		/*
4758d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		 * cfg80211 does not currently accept new connections if
4759d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		 * we are already connected. As a workaround, force
4760d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		 * disconnection and try again.
4761d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		 */
4762d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Explicitly "
4763d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			   "disconnecting before reassociation "
4764d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			   "attempt");
4765d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		if (wpa_driver_nl80211_disconnect(
4766d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			    drv, WLAN_REASON_PREV_AUTH_NOT_VALID))
4767d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			return -1;
4768d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		ret = wpa_driver_nl80211_try_connect(drv, params);
4769d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	}
4770d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	return ret;
4771d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt}
4772d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
4773d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
47748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_associate(
47758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *priv, struct wpa_driver_associate_params *params)
47768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
47778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
47788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
47796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret = -1;
47808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
47818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl80211_unmask_11b_rates(bss);
47836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
47848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->mode == IEEE80211_MODE_AP)
47858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return wpa_driver_nl80211_ap(drv, params);
47868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->mode == IEEE80211_MODE_IBSS)
47888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return wpa_driver_nl80211_ibss(drv, params);
47898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
47911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		enum nl80211_iftype nlmode = params->p2p ?
47921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
47931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
47941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
47958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
47968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return wpa_driver_nl80211_connect(drv, params);
47978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
47988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47998bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	nl80211_mark_disconnected(drv);
48008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
48028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   drv->ifindex);
48036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_ASSOCIATE);
48046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg)
48056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
48068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4807fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	ret = nl80211_connect_common(drv, params, msg);
4808fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (ret)
48096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
48108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->prev_bssid) {
48128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * prev_bssid=" MACSTR,
48138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(params->prev_bssid));
48146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
48156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    params->prev_bssid))
48166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
48178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
48188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
48208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
48218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
48221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_dbg(drv->ctx, MSG_DEBUG,
48231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			"nl80211: MLME command failed (assoc): ret=%d (%s)",
48241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			ret, strerror(-ret));
48258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_dump_scan(drv);
48266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else {
48276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
48286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Association request send successfully");
48298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
48308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
48328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
48338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
48348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
48358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
48381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    int ifindex, enum nl80211_iftype mode)
48398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
48408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
48418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -ENOBUFS;
48428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Set mode ifindex %d iftype %d (%s)",
48441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   ifindex, mode, nl80211_iftype_str(mode));
48451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
48466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
48476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg || nla_put_u32(msg, NL80211_ATTR_IFTYPE, mode))
48486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
48498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
48511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
48528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!ret)
48538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
48546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
48551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
48568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
48578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   " %d (%s)", ifindex, mode, ret, strerror(-ret));
48588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
48598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
48608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4862d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidtstatic int wpa_driver_nl80211_set_mode_impl(
4863d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		struct i802_bss *bss,
4864d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		enum nl80211_iftype nlmode,
4865d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		struct hostapd_freq_params *desired_freq_params)
48668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
48678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
48688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
48698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
48701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int was_ap = is_ap_interface(drv->nlmode);
48711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int res;
4872d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	int mode_switch_res;
48738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4874d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
4875d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	if (mode_switch_res && nlmode == nl80211_get_ifmode(bss))
4876d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		mode_switch_res = 0;
487734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
4878d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	if (mode_switch_res == 0) {
48798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->nlmode = nlmode;
48808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = 0;
48818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto done;
48828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
48838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4884d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	if (mode_switch_res == -ENODEV)
48851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
48861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
48878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nlmode == drv->nlmode) {
48888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
48898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "requested mode - ignore error");
48908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = 0;
48918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto done; /* Already in the requested mode */
48928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
48938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* mac80211 doesn't allow mode changes while the device is up, so
48958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * take the device down, try to set the mode again, and bring the
48968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * device back up.
48978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
48988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
48998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "interface down");
49008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < 10; i++) {
490134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		res = i802_set_iface_flags(bss, 0);
49021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (res == -EACCES || res == -ENODEV)
49031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
4904d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		if (res != 0) {
49058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Failed to set "
49068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "interface down");
4907d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt			os_sleep(0, 100000);
4908d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt			continue;
4909d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		}
4910d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt
4911d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		/*
4912d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		 * Setting the mode will fail for some drivers if the phy is
4913d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		 * on a frequency that the mode is disallowed in.
4914d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		 */
4915d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		if (desired_freq_params) {
49166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			res = nl80211_set_channel(bss, desired_freq_params, 0);
4917d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt			if (res) {
4918d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt				wpa_printf(MSG_DEBUG,
4919d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt					   "nl80211: Failed to set frequency on interface");
4920d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt			}
4921d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		}
4922d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt
4923d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		/* Try to set the mode again while the interface is down */
4924d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode);
4925d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		if (mode_switch_res == -EBUSY) {
4926d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt			wpa_printf(MSG_DEBUG,
4927d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt				   "nl80211: Delaying mode set while interface going down");
4928d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt			os_sleep(0, 100000);
4929d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt			continue;
4930d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		}
4931d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		ret = mode_switch_res;
4932d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		break;
49338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
49348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!ret) {
49368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
49378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "interface is down");
49388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->nlmode = nlmode;
49391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		drv->ignore_if_down_event = 1;
49408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
49418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4942d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	/* Bring the interface back up */
4943d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	res = linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1);
4944d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	if (res != 0) {
4945d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		wpa_printf(MSG_DEBUG,
4946d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt			   "nl80211: Failed to set interface up after switching mode");
4947d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt		ret = -1;
4948d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	}
4949d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt
49508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtdone:
49511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ret) {
49521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
49531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "from %d failed", nlmode, drv->nlmode);
49541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return ret;
49551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
49561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
49576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (is_p2p_net_interface(nlmode)) {
49586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
49596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Interface %s mode change to P2P - disable 11b rates",
49606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   bss->ifname);
496161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		nl80211_disable_11b_rates(drv, drv->ifindex, 1);
49626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else if (drv->disabled_11b_rates) {
49636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
49646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Interface %s mode changed to non-P2P - re-enable 11b rates",
49656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   bss->ifname);
496661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		nl80211_disable_11b_rates(drv, drv->ifindex, 0);
49676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
496861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
49691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (is_ap_interface(nlmode)) {
49701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_mgmt_unsubscribe(bss, "start AP");
49718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Setup additional AP mode functionality if needed */
49721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (nl80211_setup_ap(bss))
49738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
49741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else if (was_ap) {
49758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Remove additional AP mode functionality */
49761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_teardown_ap(bss);
49771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else {
49781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_mgmt_unsubscribe(bss, "mode change");
49798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
49808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (is_mesh_interface(nlmode) &&
49826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nl80211_mgmt_subscribe_mesh(bss))
49836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
49846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
498504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (!bss->in_deinit && !is_ap_interface(nlmode) &&
49866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    !is_mesh_interface(nlmode) &&
49871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    nl80211_mgmt_subscribe_non_ap(bss) < 0)
49881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
49891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "frame processing - ignore for now");
49908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
49928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
49938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtint wpa_driver_nl80211_set_mode(struct i802_bss *bss,
49966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				enum nl80211_iftype nlmode)
4997d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt{
4998d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	return wpa_driver_nl80211_set_mode_impl(bss, nlmode, NULL);
4999d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt}
5000d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt
5001d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt
50029ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidtstatic int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
50039ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt					    struct hostapd_freq_params *freq)
5004d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt{
5005d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt	return wpa_driver_nl80211_set_mode_impl(bss, NL80211_IFTYPE_ADHOC,
50069ead16e203b81d44a2d84eadc2901ceeb7daf805Dmitry Shmidt						freq);
5007d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt}
5008d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt
5009d30ac604c9f6da71a0dd7f46d25be05a2a62cfbbDmitry Shmidt
50108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_get_capa(void *priv,
50118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       struct wpa_driver_capa *capa)
50128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
50138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
50148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
5015d11f019d62a42a8fc4c4d1f2ec17cf35b0763153Dmitry Shmidt
50168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!drv->has_capability)
50178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
50188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(capa, &drv->capa, sizeof(*capa));
5019444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	if (drv->extended_capa && drv->extended_capa_mask) {
5020444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		capa->extended_capa = drv->extended_capa;
5021444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		capa->extended_capa_mask = drv->extended_capa_mask;
5022444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		capa->extended_capa_len = drv->extended_capa_len;
5023444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	}
502434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
50256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 0;
50268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
50278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_set_operstate(void *priv, int state)
50308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
50318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
50328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
50338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5034fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Set %s operstate %d->%d (%s)",
5035fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		   bss->ifname, drv->operstate, state,
5036fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		   state ? "UP" : "DORMANT");
50378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->operstate = state;
50381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1,
50398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      state ? IF_OPER_UP : IF_OPER_DORMANT);
50408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
50418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
50448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
50458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
50468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
50478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
50488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl80211_sta_flag_update upd;
50496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
5050fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
5051fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (!drv->associated && is_zero_ether_addr(drv->bssid) && !authorized) {
5052fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Skip set_supp_port(unauthorized) while not associated");
5053fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return 0;
5054fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
50558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50568bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for "
50578bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		   MACSTR, authorized ? "" : "un", MAC2STR(drv->bssid));
50588bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
50598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&upd, 0, sizeof(upd));
50608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED);
50618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (authorized)
50628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
50636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
50646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
50656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid) ||
50666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd)) {
50676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
50686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
50696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
50708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5071fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
5072fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (!ret)
5073fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		return 0;
5074fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to set STA flag: %d (%s)",
5075fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		   ret, strerror(-ret));
5076fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	return ret;
50778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
50788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
508075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen/* Set kernel driver on given frequency (MHz) */
508175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
50828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
508375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct i802_bss *bss = priv;
50847832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt	return nl80211_set_channel(bss, freq, 0);
50858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
50868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic inline int min_int(int a, int b)
50898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
50908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (a < b)
50918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return a;
50928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return b;
50938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
50948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int get_key_handler(struct nl_msg *msg, void *arg)
50978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
50988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
50998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
51008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
51028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
51038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
51058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * TODO: validate the key index and mac address!
51068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Otherwise, there's a race condition as soon as
51078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * the kernel starts sending key notifications.
51088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
51098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_KEY_SEQ])
51118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]),
51128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6));
51138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
51148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
51158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
51188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   int idx, u8 *seq)
51198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
51208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
51218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
51228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
51238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_ifindex_msg(drv, if_nametoindex(iface), 0,
51256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  NL80211_CMD_GET_KEY);
51266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg ||
51276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
51286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u8(msg, NL80211_ATTR_KEY_IDX, idx)) {
51296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
51306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
51316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
51328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memset(seq, 0, 6);
51348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, get_key_handler, seq);
51368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
51378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_set_rts(void *priv, int rts)
51408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
51418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
51428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
51438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
51446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
51458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 val;
51468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (rts >= 2347)
51488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val = (u32) -1;
51498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
51508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val = rts;
51518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
51536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val)) {
51546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
51556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
51566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
51578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
51598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!ret)
51608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
51618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
51628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "%d (%s)", rts, ret, strerror(-ret));
51638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
51648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
51658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_set_frag(void *priv, int frag)
51688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
51698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
51708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
51718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
51726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
51738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 val;
51748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (frag >= 2346)
51768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val = (u32) -1;
51778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
51788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val = frag;
51798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
51816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val)) {
51826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
51836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
51846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
51858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
51878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!ret)
51888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
51898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
51908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "%d: %d (%s)", frag, ret, strerror(-ret));
51918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
51928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
51938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_flush(void *priv)
51968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
51978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
51988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
51991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int res;
52008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5201b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: flush -> DEL_STATION %s (all)",
5202b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		   bss->ifname);
52038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
52058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * XXX: FIX! this needs to flush all VLANs too
52068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
52076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION);
52086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	res = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
52091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (res) {
52101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
52111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "(%s)", res, strerror(-res));
52121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
52131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return res;
52148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
52158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int get_sta_handler(struct nl_msg *msg, void *arg)
52188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
52198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
52208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
52218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostap_sta_driver_data *data = arg;
52228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *stats[NL80211_STA_INFO_MAX + 1];
52238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
52248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
52258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
52268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
52278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
52288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
52291e6c57fee4a56b421cc20f6dc0785c9138b21337Jouni Malinen		[NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
52308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
52318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
52338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
52348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
52368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * TODO: validate the interface and mac address!
52378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Otherwise, there's a race condition as soon as
52388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * the kernel starts sending station notifications.
52398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
52408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!tb[NL80211_ATTR_STA_INFO]) {
52428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "sta stats missing!");
52438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
52448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
52458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nla_parse_nested(stats, NL80211_STA_INFO_MAX,
52468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     tb[NL80211_ATTR_STA_INFO],
52478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     stats_policy)) {
52488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "failed to parse nested attributes!");
52498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
52508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
52518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (stats[NL80211_STA_INFO_INACTIVE_TIME])
52538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->inactive_msec =
52548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]);
52558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (stats[NL80211_STA_INFO_RX_BYTES])
52568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]);
52578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (stats[NL80211_STA_INFO_TX_BYTES])
52588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]);
52598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (stats[NL80211_STA_INFO_RX_PACKETS])
52608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->rx_packets =
52618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]);
52628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (stats[NL80211_STA_INFO_TX_PACKETS])
52638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->tx_packets =
52648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
52651e6c57fee4a56b421cc20f6dc0785c9138b21337Jouni Malinen	if (stats[NL80211_STA_INFO_TX_FAILED])
52661e6c57fee4a56b421cc20f6dc0785c9138b21337Jouni Malinen		data->tx_retry_failed =
52671e6c57fee4a56b421cc20f6dc0785c9138b21337Jouni Malinen			nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
52688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
52708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
52718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52724b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int i802_read_sta_data(struct i802_bss *bss,
52734b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt			      struct hostap_sta_driver_data *data,
52748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      const u8 *addr)
52758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
52768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
52778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(data, 0, sizeof(*data));
52798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_GET_STATION)) ||
52816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
52826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
52836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
52846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
52858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return send_and_recv_msgs(bss->drv, msg, get_sta_handler, data);
52878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
52888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_set_tx_queue_params(void *priv, int queue, int aifs,
52918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    int cw_min, int cw_max, int burst_time)
52928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
52938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
52948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
52958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
52968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *txq, *params;
52978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_WIPHY);
52998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
53008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
53018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
53038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!txq)
53046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
53058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* We are only sending parameters for a single TXQ at a time */
53078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	params = nla_nest_start(msg, 1);
53088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!params)
53096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
53108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (queue) {
53128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case 0:
53136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO))
53146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
53158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
53168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case 1:
53176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI))
53186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
53198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
53208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case 2:
53216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE))
53226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
53238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
53248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case 3:
53256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK))
53266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
53278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
53288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
53298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Burst time is configured in units of 0.1 msec and TXOP parameter in
53308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * 32 usec, so need to convert the value here. */
53316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_put_u16(msg, NL80211_TXQ_ATTR_TXOP,
53326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			(burst_time * 100 + 16) / 32) ||
53336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min) ||
53346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max) ||
53356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u8(msg, NL80211_TXQ_ATTR_AIFS, aifs))
53366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
53378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_nest_end(msg, params);
53398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_nest_end(msg, txq);
53418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
53438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
53441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
53456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
53461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
53478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
53488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
53498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53514b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr,
53528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     const char *ifname, int vlan_id)
53538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
53548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
53558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
53566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
53578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5358cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: %s[%d]: set_sta_vlan(" MACSTR
5359cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		   ", ifname=%s[%d], vlan_id=%d)",
5360cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		   bss->ifname, if_nametoindex(bss->ifname),
5361cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		   MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
53626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
53636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
53646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_STA_VLAN, if_nametoindex(ifname))) {
53656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
53666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
53676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
53688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
53708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
53718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
53728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
53738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(addr), ifname, vlan_id, ret,
53748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   strerror(-ret));
53758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
53768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
53778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
53788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_get_inact_sec(void *priv, const u8 *addr)
53818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
53828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostap_sta_driver_data data;
53838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
53848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.inactive_msec = (unsigned long) -1;
53868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = i802_read_sta_data(priv, &data, addr);
53872f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	if (ret == -ENOENT)
53882f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		return -ENOENT;
53898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret || data.inactive_msec == (unsigned long) -1)
53908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
53918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return data.inactive_msec / 1000;
53928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
53938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_sta_clear_stats(void *priv, const u8 *addr)
53968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
53978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if 0
53988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO */
53998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
54008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
54018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
54028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
54058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   int reason)
54068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
54078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
540804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
54098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee80211_mgmt mgmt;
54108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (is_mesh_interface(drv->nlmode))
54126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
54136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
541404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (drv->device_ap_sme)
54156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return wpa_driver_nl80211_sta_remove(bss, addr, 1, reason);
541604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
54178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memset(&mgmt, 0, sizeof(mgmt));
54188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
54198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  WLAN_FC_STYPE_DEAUTH);
54208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(mgmt.da, addr, ETH_ALEN);
54218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(mgmt.sa, own_addr, ETH_ALEN);
54228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
54238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt.u.deauth.reason_code = host_to_le16(reason);
54248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
54258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    IEEE80211_HDRLEN +
54264b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					    sizeof(mgmt.u.deauth), 0, 0, 0, 0,
54274b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					    0);
54288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
54298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
54328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     int reason)
54338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
54348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
543504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
54368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee80211_mgmt mgmt;
54378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (is_mesh_interface(drv->nlmode))
54396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
54406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
544104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (drv->device_ap_sme)
54426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return wpa_driver_nl80211_sta_remove(bss, addr, 0, reason);
544304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
54448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memset(&mgmt, 0, sizeof(mgmt));
54458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
54468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  WLAN_FC_STYPE_DISASSOC);
54478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(mgmt.da, addr, ETH_ALEN);
54488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(mgmt.sa, own_addr, ETH_ALEN);
54498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
54508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt.u.disassoc.reason_code = host_to_le16(reason);
54518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
54528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    IEEE80211_HDRLEN +
54534b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					    sizeof(mgmt.u.disassoc), 0, 0, 0, 0,
54544b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					    0);
54558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
54568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5458df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidtstatic void dump_ifidx(struct wpa_driver_nl80211_data *drv)
5459df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt{
5460df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	char buf[200], *pos, *end;
5461df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	int i, res;
5462df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
5463df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	pos = buf;
5464df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	end = pos + sizeof(buf);
5465df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
5466df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	for (i = 0; i < drv->num_if_indices; i++) {
5467df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		if (!drv->if_indices[i])
5468df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			continue;
5469df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		res = os_snprintf(pos, end - pos, " %d", drv->if_indices[i]);
54706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (os_snprintf_error(end - pos, res))
5471df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			break;
5472df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		pos += res;
5473df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	}
5474df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	*pos = '\0';
5475df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
5476df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: if_indices[%d]:%s",
5477df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		   drv->num_if_indices, buf);
5478df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt}
5479df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
5480df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
548175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
548275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
548375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	int i;
548475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	int *old;
548575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
548675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d",
548775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		   ifidx);
5488df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	if (have_ifidx(drv, ifidx)) {
5489df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: ifindex %d already in the list",
5490df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			   ifidx);
5491df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		return;
5492df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	}
549375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	for (i = 0; i < drv->num_if_indices; i++) {
549475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		if (drv->if_indices[i] == 0) {
549575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			drv->if_indices[i] = ifidx;
5496df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt			dump_ifidx(drv);
549775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			return;
549875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		}
549975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	}
550075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
550175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (drv->if_indices != drv->default_if_indices)
550275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		old = drv->if_indices;
550375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	else
550475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		old = NULL;
550575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
550661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1,
550761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					   sizeof(int));
550875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (!drv->if_indices) {
550975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		if (!old)
551075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			drv->if_indices = drv->default_if_indices;
551175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		else
551275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			drv->if_indices = old;
551375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
551475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			   "interfaces");
551575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
551675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		return;
551775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	} else if (!old)
551875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		os_memcpy(drv->if_indices, drv->default_if_indices,
551975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			  sizeof(drv->default_if_indices));
552075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	drv->if_indices[drv->num_if_indices] = ifidx;
552175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	drv->num_if_indices++;
5522df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	dump_ifidx(drv);
552375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
552475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
552575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
552675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
552775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
552875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	int i;
552975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
553075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	for (i = 0; i < drv->num_if_indices; i++) {
553175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		if (drv->if_indices[i] == ifidx) {
553275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			drv->if_indices[i] = 0;
553375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			break;
553475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		}
553575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	}
5536df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt	dump_ifidx(drv);
553775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
553875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
553975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
554075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
554175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
554275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	int i;
554375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
554475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	for (i = 0; i < drv->num_if_indices; i++)
554575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		if (drv->if_indices[i] == ifidx)
554675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			return 1;
554775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
554875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	return 0;
554975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
555075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
555175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
555275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
55537832adbbd72a1b784b7fb74a71a5d4085b0cb0d3Dmitry Shmidt			    const char *bridge_ifname, char *ifname_wds)
555475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
555575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct i802_bss *bss = priv;
555675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct wpa_driver_nl80211_data *drv = bss->drv;
555775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	char name[IFNAMSIZ + 1];
555875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
555975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
5560c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	if (ifname_wds)
5561c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		os_strlcpy(ifname_wds, name, IFNAMSIZ + 1);
5562c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
556375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
556475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		   " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
556575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (val) {
556675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		if (!if_nametoindex(name)) {
556775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			if (nl80211_create_iface(drv, name,
556875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen						 NL80211_IFTYPE_AP_VLAN,
5569cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt						 bss->addr, 1, NULL, NULL, 0) <
5570cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			    0)
557175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen				return -1;
557275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			if (bridge_ifname &&
55731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    linux_br_add_if(drv->global->ioctl_sock,
55741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					    bridge_ifname, name) < 0)
557575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen				return -1;
557675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		}
557761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) {
557861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
557961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				   "interface %s up", name);
558061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		}
558175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		return i802_set_sta_vlan(priv, addr, name, 0);
558275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	} else {
5583aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt		if (bridge_ifname)
5584aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt			linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
5585aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt					name);
5586aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt
558775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		i802_set_sta_vlan(priv, addr, bss->ifname, 0);
5588a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt		nl80211_remove_iface(drv, if_nametoindex(name));
5589a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt		return 0;
559075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	}
559175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
559275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
559375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
559475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
559575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
559675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct wpa_driver_nl80211_data *drv = eloop_ctx;
559775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct sockaddr_ll lladdr;
559875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	unsigned char buf[3000];
559975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	int len;
560075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	socklen_t fromlen = sizeof(lladdr);
560175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
560275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	len = recvfrom(sock, buf, sizeof(buf), 0,
560375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		       (struct sockaddr *)&lladdr, &fromlen);
560475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (len < 0) {
560568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: EAPOL recv failed: %s",
560668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			   strerror(errno));
560775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		return;
560875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	}
560975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
561075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (have_ifidx(drv, lladdr.sll_ifindex))
561175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
561275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
561375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
561475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
56158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
56168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     struct i802_bss *bss,
56178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     const char *brname, const char *ifname)
56188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
56196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int br_ifindex;
56208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char in_br[IFNAMSIZ];
56218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_strlcpy(bss->brname, brname, IFNAMSIZ);
56236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	br_ifindex = if_nametoindex(brname);
56246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (br_ifindex == 0) {
56258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
56268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Bridge was configured, but the bridge device does
56278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * not exist. Try to add it now.
56288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
56291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (linux_br_add(drv->global->ioctl_sock, brname) < 0) {
56308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
56318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "bridge interface %s: %s",
56328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   brname, strerror(errno));
56338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
56348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
56358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->added_bridge = 1;
56366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		br_ifindex = if_nametoindex(brname);
56376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		add_ifidx(drv, br_ifindex);
56388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
56396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	bss->br_ifindex = br_ifindex;
56408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (linux_br_get(in_br, ifname) == 0) {
56428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strcmp(in_br, brname) == 0)
56438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 0; /* already in the bridge */
56448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
56468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "bridge %s", ifname, in_br);
56471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) <
56481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    0) {
56498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "nl80211: Failed to "
56508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "remove interface %s from bridge "
56518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "%s: %s",
56528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   ifname, brname, strerror(errno));
56538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
56548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
56558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
56568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
56588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   ifname, brname);
56591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) {
56608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to add interface %s "
56618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "into bridge %s: %s",
56628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ifname, brname, strerror(errno));
56638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
56648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
56658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss->added_if_into_bridge = 1;
56668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
56688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
56698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void *i802_init(struct hostapd_data *hapd,
56728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       struct wpa_init_params *params)
56738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
56748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv;
56758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss;
56768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
56778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char brname[IFNAMSIZ];
56788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifindex, br_ifindex;
56798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int br_added = 0;
56808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5681e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt	bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
5682e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt					  params->global_priv, 1,
56836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  params->bssid, params->driver_params);
56848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss == NULL)
56858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
56868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv = bss->drv;
56881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
56898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (linux_br_get(brname, params->ifname) == 0) {
56908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
56918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   params->ifname, brname);
56928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		br_ifindex = if_nametoindex(brname);
56936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		os_strlcpy(bss->brname, brname, IFNAMSIZ);
56948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
56958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		brname[0] = '\0';
56968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		br_ifindex = 0;
56978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
56986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	bss->br_ifindex = br_ifindex;
56998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < params->num_bridge; i++) {
57018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->bridge[i]) {
57028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ifindex = if_nametoindex(params->bridge[i]);
57038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ifindex)
57048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				add_ifidx(drv, ifindex);
57058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ifindex == br_ifindex)
57068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				br_added = 1;
57078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
57088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
57098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* start listening for EAPOL on the default AP interface */
57118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	add_ifidx(drv, drv->ifindex);
57128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->num_bridge && params->bridge[0]) {
57146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (i802_check_bridge(drv, bss, params->bridge[0],
57156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				      params->ifname) < 0)
57166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto failed;
57176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (os_strcmp(params->bridge[0], brname) != 0)
57186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			br_added = 1;
57196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
57206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
57216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!br_added && br_ifindex &&
57226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (params->num_bridge == 0 || !params->bridge[0]))
57236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		add_ifidx(drv, br_ifindex);
57248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5725661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt#ifdef CONFIG_LIBNL3_ROUTE
5726661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	if (bss->added_if_into_bridge) {
5727661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		drv->rtnl_sk = nl_socket_alloc();
5728661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		if (drv->rtnl_sk == NULL) {
5729661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock");
5730661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			goto failed;
5731661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		}
5732661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
5733661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		if (nl_connect(drv->rtnl_sk, NETLINK_ROUTE)) {
5734661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s",
5735661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt				   strerror(errno));
5736661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			goto failed;
5737661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		}
5738661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	}
5739661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt#endif /* CONFIG_LIBNL3_ROUTE */
5740661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
57418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
57428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->eapol_sock < 0) {
574368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE) failed: %s",
574468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			   strerror(errno));
57458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
57468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
57478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
57498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
575068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		wpa_printf(MSG_INFO, "nl80211: Could not register read socket for eapol");
57518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
57528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
57538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
57551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			       params->own_addr))
57568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
5757661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	os_memcpy(drv->perm_addr, params->own_addr, ETH_ALEN);
57588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	memcpy(bss->addr, params->own_addr, ETH_ALEN);
57601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
57618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return bss;
57628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfailed:
57641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_driver_nl80211_deinit(bss);
57658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
57668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
57678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void i802_deinit(void *priv)
57708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
57714b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct i802_bss *bss = priv;
57724b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	wpa_driver_nl80211_deinit(bss);
57738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
57748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic enum nl80211_iftype wpa_driver_nl80211_if_type(
57778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum wpa_driver_if_type type)
57788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
57798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (type) {
57808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_IF_STATION:
57818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL80211_IFTYPE_STATION;
57828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_IF_P2P_CLIENT:
57838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_IF_P2P_GROUP:
57848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL80211_IFTYPE_P2P_CLIENT;
57858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_IF_AP_VLAN:
57868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL80211_IFTYPE_AP_VLAN;
57878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_IF_AP_BSS:
57888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL80211_IFTYPE_AP;
57898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_IF_P2P_GO:
57908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL80211_IFTYPE_P2P_GO;
579134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case WPA_IF_P2P_DEVICE:
579234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NL80211_IFTYPE_P2P_DEVICE;
57936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case WPA_IF_MESH:
57946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL80211_IFTYPE_MESH_POINT;
57958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
57968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
57978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
57988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
58018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
58028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv;
58038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each(drv, &global->interfaces,
58048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 struct wpa_driver_nl80211_data, list) {
5805cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (os_memcmp(addr, drv->first_bss->addr, ETH_ALEN) == 0)
58068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 1;
58078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
58088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
58098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
58108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_vif_addr(struct wpa_driver_nl80211_data *drv, u8 *new_addr)
58138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
58148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int idx;
58158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!drv->global)
58178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
58188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5819cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	os_memcpy(new_addr, drv->first_bss->addr, ETH_ALEN);
58208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (idx = 0; idx < 64; idx++) {
5821cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		new_addr[0] = drv->first_bss->addr[0] | 0x02;
58228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		new_addr[0] ^= idx << 2;
58238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!nl80211_addr_in_use(drv->global, new_addr))
58248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
58258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
58268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (idx == 64)
58278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
58288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Assigned new virtual interface address "
58308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   MACSTR, MAC2STR(new_addr));
58318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
58338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
58348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
583634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstruct wdev_info {
583734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u64 wdev_id;
583834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	int wdev_id_set;
583934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 macaddr[ETH_ALEN];
584034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt};
584134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
584234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int nl80211_wdev_handler(struct nl_msg *msg, void *arg)
584334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
584434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
584534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
584634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wdev_info *wi = arg;
584734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
584834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
584934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
585034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (tb[NL80211_ATTR_WDEV]) {
585134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wi->wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
585234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wi->wdev_id_set = 1;
585334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
585434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
585534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (tb[NL80211_ATTR_MAC])
585634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		os_memcpy(wi->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
585734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			  ETH_ALEN);
585834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
585934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return NL_SKIP;
586034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
586134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
586234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
58638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
58648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     const char *ifname, const u8 *addr,
58658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     void *bss_ctx, void **drv_priv,
58668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     char *force_ifname, u8 *if_addr,
5867cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				     const char *bridge, int use_existing)
58688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
586934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	enum nl80211_iftype nlmode;
58708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
58718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
58728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifidx;
5873cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	int added = 1;
58748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (addr)
58768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(if_addr, addr, ETH_ALEN);
587734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	nlmode = wpa_driver_nl80211_if_type(type);
587834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
587934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		struct wdev_info p2pdev_info;
588034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
588134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		os_memset(&p2pdev_info, 0, sizeof(p2pdev_info));
588234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
588334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					     0, nl80211_wdev_handler,
5884cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt					     &p2pdev_info, use_existing);
588534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (!p2pdev_info.wdev_id_set || ifidx != 0) {
588634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
588734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				   ifname);
588834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			return -1;
588934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		}
589034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
589134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		drv->global->if_add_wdevid = p2pdev_info.wdev_id;
589234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		drv->global->if_add_wdevid_set = p2pdev_info.wdev_id_set;
589334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (!is_zero_ether_addr(p2pdev_info.macaddr))
589434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			os_memcpy(if_addr, p2pdev_info.macaddr, ETH_ALEN);
589534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: New P2P Device interface %s (0x%llx) created",
589634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   ifname,
589734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   (long long unsigned int) p2pdev_info.wdev_id);
589834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	} else {
589934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
5900cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt					     0, NULL, NULL, use_existing);
5901cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (use_existing && ifidx == -ENFILE) {
5902cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			added = 0;
5903cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			ifidx = if_nametoindex(ifname);
5904cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		} else if (ifidx < 0) {
590534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			return -1;
590634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		}
59078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
59088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
590934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (!addr) {
59101d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt		if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
591134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			os_memcpy(if_addr, bss->addr, ETH_ALEN);
591234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
59131d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt					    ifname, if_addr) < 0) {
5914cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			if (added)
5915cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				nl80211_remove_iface(drv, ifidx);
591634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			return -1;
591734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		}
59188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
59198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!addr &&
59218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
59221d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt	     type == WPA_IF_P2P_GO || type == WPA_IF_MESH ||
59231d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt	     type == WPA_IF_STATION)) {
59241d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt		/* Enforce unique address */
592534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		u8 new_addr[ETH_ALEN];
59268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
592734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
59281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				       new_addr) < 0) {
5929717574375e969e8272c6d1a26137286eac158abbDmitry Shmidt			if (added)
5930717574375e969e8272c6d1a26137286eac158abbDmitry Shmidt				nl80211_remove_iface(drv, ifidx);
59318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
59328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
593334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (nl80211_addr_in_use(drv->global, new_addr)) {
59348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
59351d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidt				   "for interface %s type %d", ifname, type);
59366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			if (nl80211_vif_addr(drv, new_addr) < 0) {
5937717574375e969e8272c6d1a26137286eac158abbDmitry Shmidt				if (added)
5938717574375e969e8272c6d1a26137286eac158abbDmitry Shmidt					nl80211_remove_iface(drv, ifidx);
59398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return -1;
59408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
59411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
59428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       new_addr) < 0) {
5943717574375e969e8272c6d1a26137286eac158abbDmitry Shmidt				if (added)
5944717574375e969e8272c6d1a26137286eac158abbDmitry Shmidt					nl80211_remove_iface(drv, ifidx);
59458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return -1;
59468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
59478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
59486e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidt		os_memcpy(if_addr, new_addr, ETH_ALEN);
59498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
59508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (type == WPA_IF_AP_BSS) {
595268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
595368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		if (new_bss == NULL) {
5954cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			if (added)
5955cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				nl80211_remove_iface(drv, ifidx);
595668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			return -1;
595768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		}
595868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
595968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		if (bridge &&
596068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		    i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
596168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
596268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt				   "interface %s to a bridge %s",
596368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt				   ifname, bridge);
5964cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			if (added)
5965cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt				nl80211_remove_iface(drv, ifidx);
596668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			os_free(new_bss);
596768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			return -1;
596868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		}
596968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
59701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
59711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		{
5972717574375e969e8272c6d1a26137286eac158abbDmitry Shmidt			if (added)
5973717574375e969e8272c6d1a26137286eac158abbDmitry Shmidt				nl80211_remove_iface(drv, ifidx);
59748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(new_bss);
59758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
59768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
59778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
59781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
59798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		new_bss->ifindex = ifidx;
59808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		new_bss->drv = drv;
5981cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		new_bss->next = drv->first_bss->next;
5982cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		new_bss->freq = drv->first_bss->freq;
5983a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		new_bss->ctx = bss_ctx;
5984cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		new_bss->added_if = added;
5985cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		drv->first_bss->next = new_bss;
59868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (drv_priv)
59878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			*drv_priv = new_bss;
59881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_init_bss(new_bss);
5989c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
5990c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		/* Subscribe management frames for this WPA_IF_AP_BSS */
5991c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		if (nl80211_setup_ap(new_bss))
5992c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			return -1;
59938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
59948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->global)
59961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		drv->global->if_add_ifindex = ifidx;
59971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
599843cb578dfe2c492257636f6234a24178ed27789eDmitry Shmidt	/*
599943cb578dfe2c492257636f6234a24178ed27789eDmitry Shmidt	 * Some virtual interfaces need to process EAPOL packets and events on
600043cb578dfe2c492257636f6234a24178ed27789eDmitry Shmidt	 * the parent interface. This is used mainly with hostapd.
600143cb578dfe2c492257636f6234a24178ed27789eDmitry Shmidt	 */
600243cb578dfe2c492257636f6234a24178ed27789eDmitry Shmidt	if (ifidx > 0 &&
600343cb578dfe2c492257636f6234a24178ed27789eDmitry Shmidt	    (drv->hostapd ||
600443cb578dfe2c492257636f6234a24178ed27789eDmitry Shmidt	     nlmode == NL80211_IFTYPE_AP_VLAN ||
600543cb578dfe2c492257636f6234a24178ed27789eDmitry Shmidt	     nlmode == NL80211_IFTYPE_WDS ||
600643cb578dfe2c492257636f6234a24178ed27789eDmitry Shmidt	     nlmode == NL80211_IFTYPE_MONITOR))
6007df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt		add_ifidx(drv, ifidx);
6008df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt
60098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
60108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
60118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60134b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
60148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					enum wpa_driver_if_type type,
60158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					const char *ifname)
60168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
60178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
60188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifindex = if_nametoindex(ifname);
60198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6020cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d added_if=%d",
6021cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		   __func__, type, ifname, ifindex, bss->added_if);
602201904cfafd75a70b9f29c0220b90bdef45595491Dmitry Shmidt	if (ifindex > 0 && (bss->added_if || bss->ifindex != ifindex))
6023051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		nl80211_remove_iface(drv, ifindex);
602476cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt	else if (ifindex > 0 && !bss->added_if) {
602576cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt		struct wpa_driver_nl80211_data *drv2;
602676cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt		dl_list_for_each(drv2, &drv->global->interfaces,
602776cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt				 struct wpa_driver_nl80211_data, list)
602876cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt			del_ifidx(drv2, ifindex);
602976cd2cc44b62e858f1897ce58f4ce7d0174e8839Dmitry Shmidt	}
6030aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt
6031aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt	if (type != WPA_IF_AP_BSS)
6032aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt		return 0;
6033aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt
60348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss->added_if_into_bridge) {
60351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
60361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				    bss->ifname) < 0)
60378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
60388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "interface %s from bridge %s: %s",
60398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   bss->ifname, bss->brname, strerror(errno));
60408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
60418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss->added_bridge) {
60421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
60438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
60448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "bridge %s: %s",
60458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   bss->brname, strerror(errno));
60468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
60478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6048cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	if (bss != drv->first_bss) {
60498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct i802_bss *tbss;
60508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6051cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Not the first BSS - remove it");
6052cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		for (tbss = drv->first_bss; tbss; tbss = tbss->next) {
60538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (tbss->next == bss) {
60548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				tbss->next = bss->next;
6055c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				/* Unsubscribe management frames */
6056c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				nl80211_teardown_ap(bss);
60571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				nl80211_destroy_bss(bss);
6058df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt				if (!bss->added_if)
6059df5a7e4c5c64890c2425bb47d665bbce4992b676Dmitry Shmidt					i802_set_iface_flags(bss, 0);
60608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				os_free(bss);
60618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				bss = NULL;
60628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
60638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
60648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
60658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (bss)
60668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "nl80211: %s - could not find "
60678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "BSS %p in the list", __func__, bss);
6068cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	} else {
6069cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: First BSS - reassign context");
6070cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		nl80211_teardown_ap(bss);
6071cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (!bss->added_if && !drv->first_bss->next)
6072cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			wpa_driver_nl80211_del_beacon(drv);
6073cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		nl80211_destroy_bss(bss);
6074cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (!bss->added_if)
6075cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			i802_set_iface_flags(bss, 0);
6076cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		if (drv->first_bss->next) {
6077cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			drv->first_bss = drv->first_bss->next;
6078cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			drv->ctx = drv->first_bss->ctx;
6079cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			os_free(bss);
6080cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		} else {
6081cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: No second BSS to reassign context to");
6082cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt		}
60838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
60848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
60868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
60878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int cookie_handler(struct nl_msg *msg, void *arg)
60908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
60918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
60928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
60938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u64 *cookie = arg;
60948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
60958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
60968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_COOKIE])
60978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
60988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
60998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
61008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_send_frame_cmd(struct i802_bss *bss,
61038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  unsigned int freq, unsigned int wait,
61048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  const u8 *buf, size_t buf_len,
61051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				  u64 *cookie_out, int no_cck, int no_ack,
61061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				  int offchanok)
61078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
61081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
61098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
61108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u64 cookie;
61118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
61128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61138da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	wpa_printf(MSG_MSGDUMP, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
611404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		   "no_ack=%d offchanok=%d",
611504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		   freq, wait, no_cck, no_ack, offchanok);
6116c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "CMD_FRAME", buf, buf_len);
61178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME)) ||
61196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (freq && nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
61206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (wait && nla_put_u32(msg, NL80211_ATTR_DURATION, wait)) ||
61216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (offchanok && ((drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
61226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   drv->test_use_roc_tx) &&
61236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK)) ||
61246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (no_cck && nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE)) ||
61256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (no_ack && nla_put_flag(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK)) ||
61266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_FRAME, buf_len, buf))
61276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
61288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cookie = 0;
61308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
61318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
61328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
61338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
61346e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidt			   "(%s) (freq=%u wait=%u)", ret, strerror(-ret),
61356e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidt			   freq, wait);
61366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else {
61376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_MSGDUMP, "nl80211: Frame TX command accepted%s; "
61386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "cookie 0x%llx", no_ack ? " (no ACK)" : "",
61396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   (long long unsigned int) cookie);
61408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (cookie_out)
61426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			*cookie_out = no_ack ? (u64) -1 : cookie;
61436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
61448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
61468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
61478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
61488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
61498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61514b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int wpa_driver_nl80211_send_action(struct i802_bss *bss,
61524b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					  unsigned int freq,
61538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  unsigned int wait_time,
61548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  const u8 *dst, const u8 *src,
61558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  const u8 *bssid,
61561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					  const u8 *data, size_t data_len,
61571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					  int no_cck)
61588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
61598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
61608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
61618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *buf;
61628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee80211_hdr *hdr;
61638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
6165c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		   "freq=%u MHz wait=%d ms no_cck=%d)",
6166c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		   drv->ifindex, freq, wait_time, no_cck);
61678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = os_zalloc(24 + data_len);
61698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
61708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ret;
61718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(buf + 24, data, data_len);
61728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = (struct ieee80211_hdr *) buf;
61738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr->frame_control =
61748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
61758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(hdr->addr1, dst, ETH_ALEN);
61768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(hdr->addr2, src, ETH_ALEN);
61778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(hdr->addr3, bssid, ETH_ALEN);
61788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61795605286c30e1701491bd3af974ae423727750eddDmitry Shmidt	if (is_ap_interface(drv->nlmode) &&
61805605286c30e1701491bd3af974ae423727750eddDmitry Shmidt	    (!(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
61815605286c30e1701491bd3af974ae423727750eddDmitry Shmidt	     (int) freq == bss->freq || drv->device_ap_sme ||
61825605286c30e1701491bd3af974ae423727750eddDmitry Shmidt	     !drv->use_monitor))
61834b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt		ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
61844b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt						   0, freq, no_cck, 1,
61854b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt						   wait_time);
61868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
61871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
61888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     24 + data_len,
61891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					     &drv->send_action_cookie,
61901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					     no_cck, 0, 1);
61918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(buf);
61938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
61948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
61958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
61988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
61998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
62008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
62018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
62028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
62038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62042f3b8dec59373945c5feef8a78ced8967a80cc66Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Cancel TX frame wait: cookie=0x%llx",
62052f3b8dec59373945c5feef8a78ced8967a80cc66Dmitry Shmidt		   (long long unsigned int) drv->send_action_cookie);
62066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME_WAIT_CANCEL)) ||
62076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie)) {
62086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
62096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return;
62106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
62118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
62138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret)
62148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
62158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", ret, strerror(-ret));
62168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
62178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
62208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						unsigned int duration)
62218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
62228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
62238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
62248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
62258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
62268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u64 cookie;
62278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REMAIN_ON_CHANNEL)) ||
62296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
62306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_DURATION, duration)) {
62316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
62328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
62336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
62348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cookie = 0;
62368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
62378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == 0) {
62388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
62398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "0x%llx for freq=%u MHz duration=%u",
62408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (long long unsigned int) cookie, freq, duration);
62418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->remain_on_chan_cookie = cookie;
62421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		drv->pending_remain_on_chan = 1;
62438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
62448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
62458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
62468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "(freq=%d duration=%u): %d (%s)",
62478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   freq, duration, ret, strerror(-ret));
62488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
62498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
62508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
62538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
62548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
62558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
62568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
62578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
62588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!drv->pending_remain_on_chan) {
62608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: No pending remain-on-channel "
62618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "to cancel");
62628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
62638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
62648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Cancel remain-on-channel with cookie "
62668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "0x%llx",
62678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (long long unsigned int) drv->remain_on_chan_cookie);
62688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
62706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg ||
62716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie)) {
62726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
62738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
62746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
62758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
62778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == 0)
62788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
62798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
62808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "%d (%s)", ret, strerror(-ret));
62818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
62828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
62838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62854b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
62868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
62878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
62886e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidt
62898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!report) {
62901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (bss->nl_preq && drv->device_ap_sme &&
629103658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt		    is_ap_interface(drv->nlmode) && !bss->in_deinit &&
629203658834c33748b9ad86f3d4cdf0c7be9c6887d1Dmitry Shmidt		    !bss->static_ap) {
62931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			/*
62941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 * Do not disable Probe Request reporting that was
62951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 * enabled in nl80211_setup_ap().
62961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 */
62971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Skip disabling of "
62981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "Probe Request reporting nl_preq=%p while "
62991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "in AP mode", bss->nl_preq);
63001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		} else if (bss->nl_preq) {
63011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
63021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "reporting nl_preq=%p", bss->nl_preq);
630368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			nl80211_destroy_eloop_handle(&bss->nl_preq);
63048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
63058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
63068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
63078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (bss->nl_preq) {
63098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting "
63101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "already on! nl_preq=%p", bss->nl_preq);
63118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
63128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
63138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	bss->nl_preq = nl_create_handle(drv->global->nl_cb, "preq");
63151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (bss->nl_preq == NULL)
63168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
63171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Enable Probe Request "
63181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   "reporting nl_preq=%p", bss->nl_preq);
63198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211_register_frame(bss, bss->nl_preq,
63218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   (WLAN_FC_TYPE_MGMT << 2) |
63228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   (WLAN_FC_STYPE_PROBE_REQ << 4),
63231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   NULL, 0) < 0)
63241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto out_err;
6325497c1d5e50162d6b3c1cce5dbd9c5fd9da69aaefDmitry Shmidt
632668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	nl80211_register_eloop_read(&bss->nl_preq,
632768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt				    wpa_driver_nl80211_event_receive,
632868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt				    bss->nl_cb);
63298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
63318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt out_err:
63331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_destroy_handles(&bss->nl_preq);
63348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
63358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
63368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
63398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     int ifindex, int disabled)
63408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
63418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
63428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *bands, *band;
63438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
63448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG,
63466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   "nl80211: NL80211_CMD_SET_TX_BITRATE_MASK (ifindex=%d %s)",
63476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   ifindex, disabled ? "NL80211_TXRATE_LEGACY=OFDM-only" :
63486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   "no NL80211_TXRATE_LEGACY constraint");
63496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
63506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_ifindex_msg(drv, ifindex, 0,
63516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  NL80211_CMD_SET_TX_BITRATE_MASK);
63528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
63538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
63548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
63568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!bands)
63576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
63588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
63608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything
63618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS
63628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * rates. All 5 GHz rates are left enabled.
63638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
63648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	band = nla_nest_start(msg, NL80211_BAND_2GHZ);
63656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!band ||
63666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (disabled && nla_put(msg, NL80211_TXRATE_LEGACY, 8,
63676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				 "\x0c\x12\x18\x24\x30\x48\x60\x6c")))
63686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
63698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_nest_end(msg, band);
63708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_nest_end(msg, bands);
63728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
63748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
63758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
63768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", ret, strerror(-ret));
637761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	} else
637861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		drv->disabled_11b_rates = disabled;
637961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
63808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
63818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
63838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
63848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
63858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
63868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_deinit_ap(void *priv)
63898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
63908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
63918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
63921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!is_ap_interface(drv->nlmode))
63938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
63948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_driver_nl80211_del_beacon(drv);
63956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	bss->beacon_set = 0;
6396b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
6397b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	/*
6398b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	 * If the P2P GO interface was dynamically added, then it is
6399b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	 * possible that the interface change to station is not possible.
6400b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	 */
6401b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (drv->nlmode == NL80211_IFTYPE_P2P_GO && bss->if_dynamic)
6402b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return 0;
6403b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
64041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
64058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
64068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6408ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidtstatic int wpa_driver_nl80211_stop_ap(void *priv)
6409ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt{
6410ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	struct i802_bss *bss = priv;
6411ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
6412ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	if (!is_ap_interface(drv->nlmode))
6413ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		return -1;
6414ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	wpa_driver_nl80211_del_beacon(drv);
6415ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	bss->beacon_set = 0;
6416ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	return 0;
6417ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt}
6418ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
6419ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
642004949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
642104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
642204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct i802_bss *bss = priv;
642304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
642404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT)
642504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return -1;
6426b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
6427b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	/*
6428b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	 * If the P2P Client interface was dynamically added, then it is
6429b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	 * possible that the interface change to station is not possible.
6430b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	 */
6431b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (bss->if_dynamic)
6432b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return 0;
6433b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
64346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
64358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
64368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void wpa_driver_nl80211_resume(void *priv)
64398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
64408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
64418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (i802_set_iface_flags(bss, 1))
64436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on resume event");
64448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
64458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
64488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
64498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
64508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
64518da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	struct nl_msg *msg;
64528da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	struct nlattr *cqm;
64538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
64558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "hysteresis=%d", threshold, hysteresis);
64568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_CQM)) ||
64586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    !(cqm = nla_nest_start(msg, NL80211_ATTR_CQM)) ||
64596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold) ||
64606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis)) {
64616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
64628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
64636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
64648da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	nla_nest_end(msg, cqm);
64658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
64678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
64688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
647034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int get_channel_width(struct nl_msg *msg, void *arg)
647134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
647234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
647334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
647434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wpa_signal_info *sig_change = arg;
647534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
647634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
647734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
647834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
647934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	sig_change->center_frq1 = -1;
648034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	sig_change->center_frq2 = -1;
648134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	sig_change->chanwidth = CHAN_WIDTH_UNKNOWN;
648234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
648334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (tb[NL80211_ATTR_CHANNEL_WIDTH]) {
648434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		sig_change->chanwidth = convert2width(
648534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
648634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (tb[NL80211_ATTR_CENTER_FREQ1])
648734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			sig_change->center_frq1 =
648834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
648934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (tb[NL80211_ATTR_CENTER_FREQ2])
649034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			sig_change->center_frq2 =
649134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
649234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
649334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
649434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return NL_SKIP;
649534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
649634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
649734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
649834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int nl80211_get_channel_width(struct wpa_driver_nl80211_data *drv,
649934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				     struct wpa_signal_info *sig)
650034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
650134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct nl_msg *msg;
650234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
65036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
650434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return send_and_recv_msgs(drv, msg, get_channel_width, sig);
650534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
650634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
650734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
65088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
65098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
65108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
65118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
65128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res;
65138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(si, 0, sizeof(*si));
65158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = nl80211_get_link_signal(drv, si);
65168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res != 0)
65178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return res;
65188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
651934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	res = nl80211_get_channel_width(drv, si);
652034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (res != 0)
652134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return res;
652234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
65238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return nl80211_get_link_noise(drv, si);
65248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
65258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
65281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			      int encrypt)
65291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
65301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct i802_bss *bss = priv;
6531c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0,
6532c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					     0, 0, 0, 0);
65338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
65348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_set_param(void *priv, const char *param)
65378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
65388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: driver param='%s'", param);
65398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (param == NULL)
65408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
65418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
65438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strstr(param, "use_p2p_group_interface=1")) {
65448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct i802_bss *bss = priv;
65458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wpa_driver_nl80211_data *drv = bss->drv;
65468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
65488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "interface");
65498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
65508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
65518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
65528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
65538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6554fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (os_strstr(param, "use_monitor=1")) {
6555fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		struct i802_bss *bss = priv;
6556fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		struct wpa_driver_nl80211_data *drv = bss->drv;
6557fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		drv->use_monitor = 1;
6558fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
6559fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
6560fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (os_strstr(param, "force_connect_cmd=1")) {
6561fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		struct i802_bss *bss = priv;
6562fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		struct wpa_driver_nl80211_data *drv = bss->drv;
6563fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		drv->capa.flags &= ~WPA_DRIVER_FLAGS_SME;
6564661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		drv->force_connect_cmd = 1;
6565fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	}
6566fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
65677d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	if (os_strstr(param, "no_offchannel_tx=1")) {
65687d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt		struct i802_bss *bss = priv;
65697d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt		struct wpa_driver_nl80211_data *drv = bss->drv;
65707d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt		drv->capa.flags &= ~WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
65717d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt		drv->test_use_roc_tx = 1;
65727d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt	}
65737d5c8f257a74ac0d12828962a492e8b84ef83923Dmitry Shmidt
65748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
65758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
65768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void * nl80211_global_init(void)
65798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
65808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl80211_global *global;
65811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct netlink_config *cfg;
65821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
65838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	global = os_zalloc(sizeof(*global));
65848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global == NULL)
65858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
65861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	global->ioctl_sock = -1;
65878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_init(&global->interfaces);
65881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	global->if_add_ifindex = -1;
65891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
65901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	cfg = os_zalloc(sizeof(*cfg));
65911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (cfg == NULL)
65921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto err;
65931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
65941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	cfg->ctx = global;
65951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
65961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
65971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	global->netlink = netlink_init(cfg);
65981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (global->netlink == NULL) {
65991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		os_free(cfg);
66001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto err;
66011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
66021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
66031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (wpa_driver_nl80211_init_nl_global(global) < 0)
66041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto err;
66051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
66061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
66071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (global->ioctl_sock < 0) {
660868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: socket(PF_INET,SOCK_DGRAM) failed: %s",
660968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			   strerror(errno));
66101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto err;
66111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
66121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
66138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return global;
66141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
66151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidterr:
66161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_global_deinit(global);
66171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return NULL;
66188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
66198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
66208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
66218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_global_deinit(void *priv)
66228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
66238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl80211_global *global = priv;
66248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global == NULL)
66258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
66268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!dl_list_empty(&global->interfaces)) {
66278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: %u interface(s) remain at "
66288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "nl80211_global_deinit",
66298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   dl_list_len(&global->interfaces));
66308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
66311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
66321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (global->netlink)
66331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		netlink_deinit(global->netlink);
66341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
66351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_destroy_handles(&global->nl);
66361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
663768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	if (global->nl_event)
663868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		nl80211_destroy_eloop_handle(&global->nl_event);
66391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
66401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_cb_put(global->nl_cb);
66411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
66426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (global->ioctl_sock >= 0)
66436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		close(global->ioctl_sock);
66446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
66456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_free(global);
66466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
66476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
66486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
66496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic const char * nl80211_get_radio_name(void *priv)
66506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
66516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
66526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
66536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return drv->phyname;
66546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
66556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
66566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
66576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid,
66586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 const u8 *pmkid)
66596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
66606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
66616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
66626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
66636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (pmkid && nla_put(msg, NL80211_ATTR_PMKID, 16, pmkid)) ||
66646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (bssid && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))) {
66656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
66666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
66676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
66686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
66696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
66706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
66716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
66726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
66736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_add_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
66746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
66756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
66766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR, MAC2STR(bssid));
66776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, bssid, pmkid);
66786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
66796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
66806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
66816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_remove_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
66826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
66836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
66846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
66856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   MAC2STR(bssid));
66866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, bssid, pmkid);
66876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
66886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
66896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
66906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_flush_pmkid(void *priv)
66916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
66926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
66936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs");
66946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return nl80211_pmkid(bss, NL80211_CMD_FLUSH_PMKSA, NULL, NULL);
66956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
66966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
66976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
66986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void clean_survey_results(struct survey_results *survey_results)
66996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
67006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct freq_survey *survey, *tmp;
67016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (dl_list_empty(&survey_results->survey_list))
67036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return;
67046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
67066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			      struct freq_survey, list) {
67076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		dl_list_del(&survey->list);
67086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		os_free(survey);
67096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
67106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
67116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void add_survey(struct nlattr **sinfo, u32 ifidx,
67146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		       struct dl_list *survey_list)
67156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
67166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct freq_survey *survey;
67176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	survey = os_zalloc(sizeof(struct freq_survey));
67196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if  (!survey)
67206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return;
67216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	survey->ifidx = ifidx;
67236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	survey->freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
67246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	survey->filled = 0;
67256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (sinfo[NL80211_SURVEY_INFO_NOISE]) {
67276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		survey->nf = (int8_t)
67286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
67296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		survey->filled |= SURVEY_HAS_NF;
67306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
67316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]) {
67336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		survey->channel_time =
67346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]);
67356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		survey->filled |= SURVEY_HAS_CHAN_TIME;
67366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
67376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]) {
67396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		survey->channel_time_busy =
67406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]);
67416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		survey->filled |= SURVEY_HAS_CHAN_TIME_BUSY;
67426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
67436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]) {
67456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		survey->channel_time_rx =
67466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]);
67476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		survey->filled |= SURVEY_HAS_CHAN_TIME_RX;
67486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
67496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]) {
67516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		survey->channel_time_tx =
67526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]);
67536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		survey->filled |= SURVEY_HAS_CHAN_TIME_TX;
67546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
67556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Freq survey dump event (freq=%d MHz noise=%d channel_time=%ld busy_time=%ld tx_time=%ld rx_time=%ld filled=%04x)",
67576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   survey->freq,
67586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   survey->nf,
67596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   (unsigned long int) survey->channel_time,
67606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   (unsigned long int) survey->channel_time_busy,
67616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   (unsigned long int) survey->channel_time_tx,
67626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   (unsigned long int) survey->channel_time_rx,
67636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   survey->filled);
67646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	dl_list_add_tail(survey_list, &survey->list);
67666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
67676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int check_survey_ok(struct nlattr **sinfo, u32 surveyed_freq,
67706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   unsigned int freq_filter)
67716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
67726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!freq_filter)
67736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return 1;
67746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return freq_filter == surveyed_freq;
67766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
67776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int survey_handler(struct nl_msg *msg, void *arg)
67806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
67816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
67826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
67836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
67846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct survey_results *survey_results;
67856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	u32 surveyed_freq = 0;
67866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	u32 ifidx;
67876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
67896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
67906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		[NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
67916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	};
67926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	survey_results = (struct survey_results *) arg;
67946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
67966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
67976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
67986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!tb[NL80211_ATTR_IFINDEX])
67996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
68006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
68016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
68026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
68036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!tb[NL80211_ATTR_SURVEY_INFO])
68046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
68056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
68066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
68076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			     tb[NL80211_ATTR_SURVEY_INFO],
68086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			     survey_policy))
68096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
68106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
68116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) {
68126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Invalid survey data");
68136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
68146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
68156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
68166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	surveyed_freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
68176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
68186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!check_survey_ok(sinfo, surveyed_freq,
68196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			     survey_results->freq_filter))
68206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
68216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
68226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (survey_results->freq_filter &&
68236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    survey_results->freq_filter != surveyed_freq) {
68246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_EXCESSIVE, "nl80211: Ignoring survey data for freq %d MHz",
68256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   surveyed_freq);
68266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
68276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
68286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
68296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	add_survey(sinfo, ifidx, &survey_results->survey_list);
68306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
68316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return NL_SKIP;
68326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
68336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
68346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
68356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_nl80211_get_survey(void *priv, unsigned int freq)
68366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
68376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
68386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
68396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
68406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int err;
68416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	union wpa_event_data data;
68426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct survey_results *survey_results;
68436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
68446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_memset(&data, 0, sizeof(data));
68456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	survey_results = &data.survey_results;
68466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
68476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	dl_list_init(&survey_results->survey_list);
68486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
68496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
68506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg)
68516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
68526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
68536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (freq)
68546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		data.survey_results.freq_filter = freq;
68556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
68566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	do {
68576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Fetch survey data");
68586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		err = send_and_recv_msgs(drv, msg, survey_handler,
68596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					 survey_results);
68606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} while (err > 0);
68616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
68626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (err)
68636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to process survey data");
68646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	else
68656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_SURVEY, &data);
68661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
68676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	clean_survey_results(survey_results);
68686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return err;
68698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
68708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6872807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidtstatic void nl80211_set_rekey_info(void *priv, const u8 *kek, size_t kek_len,
6873807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt				   const u8 *kck, size_t kck_len,
68746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   const u8 *replay_ctr)
68758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
68768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
68778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
68786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *replay_nested;
68796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
6880ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	int ret;
68816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6882ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (!drv->set_rekey_offload)
6883ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return;
6884ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
6885ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Set rekey offload");
68866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_REKEY_OFFLOAD)) ||
68876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    !(replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA)) ||
6888807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	    nla_put(msg, NL80211_REKEY_DATA_KEK, kek_len, kek) ||
6889807291d85bf857320aff6a8ade38c5f622ab9df8Dmitry Shmidt	    nla_put(msg, NL80211_REKEY_DATA_KCK, kck_len, kck) ||
68906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
68916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    replay_ctr)) {
68926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl80211_nlmsg_clear(msg);
68936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
68946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return;
68956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
68966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
68976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nla_nest_end(msg, replay_nested);
68986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
6899ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
6900ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (ret == -EOPNOTSUPP) {
6901ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_printf(MSG_DEBUG,
6902ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			   "nl80211: Driver does not support rekey offload");
6903ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		drv->set_rekey_offload = 0;
6904ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
69058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
69068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
69078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
69086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
69096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    const u8 *addr, int qos)
691075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
69116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* send data frame to poll STA and check whether
69126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	 * this frame is ACKed */
69136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct {
69146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		struct ieee80211_hdr hdr;
69156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		u16 qos_ctl;
69166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} STRUCT_PACKED nulldata;
69176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	size_t size;
691875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
69196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* Send data frame to poll STA and check whether this frame is ACKed */
692075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
69216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_memset(&nulldata, 0, sizeof(nulldata));
69226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
69236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (qos) {
69246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nulldata.hdr.frame_control =
69256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			IEEE80211_FC(WLAN_FC_TYPE_DATA,
69266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				     WLAN_FC_STYPE_QOS_NULL);
69276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		size = sizeof(nulldata);
69286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else {
69296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nulldata.hdr.frame_control =
69306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			IEEE80211_FC(WLAN_FC_TYPE_DATA,
69316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				     WLAN_FC_STYPE_NULLFUNC);
69326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		size = sizeof(struct ieee80211_hdr);
69336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
693475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
69356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
69366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
69376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
69386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
693975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
69406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0,
69416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					 0, 0) < 0)
69426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
69436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "send poll frame");
694475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
694575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
69466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
69476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				int qos)
694875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
694975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct i802_bss *bss = priv;
69506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
69516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
69527f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	int ret;
695375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
69546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!drv->poll_command_supported) {
69556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl80211_send_null_frame(bss, own_addr, addr, qos);
69566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return;
69576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
695875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
69596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_PROBE_CLIENT)) ||
69606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
69616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
69626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return;
69636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
69646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
69657f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
69667f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	if (ret < 0) {
69677f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Client probe request for "
69687f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt			   MACSTR " failed: ret=%d (%s)",
69697f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt			   MAC2STR(addr), ret, strerror(-ret));
69707f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	}
697175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
697275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
697375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
69746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_set_power_save(struct i802_bss *bss, int enabled)
697575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
69766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
69776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
69786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_POWER_SAVE)) ||
69796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_PS_STATE,
69806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED)) {
69816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
69826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
69836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
69846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
698575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
698675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
698775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
69886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
69896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				     int ctwindow)
6990b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{
69916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
6992b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
69936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
69946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
6995b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
69966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (opp_ps != -1 || ctwindow != -1) {
69976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef ANDROID_P2P
69986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_driver_set_p2p_ps(priv, legacy_ps, opp_ps, ctwindow);
69996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#else /* ANDROID_P2P */
70006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1; /* Not yet supported */
70016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* ANDROID_P2P */
7002b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	}
70036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
70046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (legacy_ps == -1)
70056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return 0;
70066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (legacy_ps != 0 && legacy_ps != 1)
70076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1; /* Not yet supported */
70086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
70096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return nl80211_set_power_save(bss, legacy_ps);
7010b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt}
7011b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
7012b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
70136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_start_radar_detection(void *priv,
70146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					 struct hostapd_freq_params *freq)
7015b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{
70166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
70176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
70186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
70196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
7020b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
70216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Start radar detection (CAC) %d MHz (ht_enabled=%d, vht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
70226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   freq->freq, freq->ht_enabled, freq->vht_enabled,
70236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   freq->bandwidth, freq->center_freq1, freq->center_freq2);
7024b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
70256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_RADAR)) {
70266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Driver does not support radar "
70276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "detection");
70286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
7029b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	}
7030b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
70316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_RADAR_DETECT)) ||
70326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nl80211_put_freq_params(msg, freq) < 0) {
70336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
70346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
7035b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	}
7036b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
70376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
70386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret == 0)
70396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return 0;
70406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
70416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   "%d (%s)", ret, strerror(-ret));
70426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return -1;
70436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
7044b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
70456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_TDLS
7046b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
70476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
70486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  u8 dialog_token, u16 status_code,
70496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  u32 peer_capab, int initiator, const u8 *buf,
70506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  size_t len)
70516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
70526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
70536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
70546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
7055b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
70566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
70576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -EOPNOTSUPP;
7058b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
70596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!dst)
70606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -EINVAL;
7061b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
70626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_MGMT)) ||
70636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
70646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u8(msg, NL80211_ATTR_TDLS_ACTION, action_code) ||
70656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token) ||
70666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, status_code))
70676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
70686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (peer_capab) {
70696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		/*
70706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * The internal enum tdls_peer_capability definition is
70716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * currently identical with the nl80211 enum
70726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * nl80211_tdls_peer_capability, so no conversion is needed
70736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 * here.
70746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		 */
70756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u32(msg, NL80211_ATTR_TDLS_PEER_CAPABILITY,
70766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				peer_capab))
70776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
70786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
70796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if ((initiator &&
70806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_flag(msg, NL80211_ATTR_TDLS_INITIATOR)) ||
70816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_IE, len, buf))
70826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
7083b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
70846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
7085b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
70866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
70876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nlmsg_free(msg);
70886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return -ENOBUFS;
7089b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt}
7090b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
7091b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
70926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
7093b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{
70946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
70956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
70966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
70976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	enum nl80211_tdls_operation nl80211_oper;
7098b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
70996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
71006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -EOPNOTSUPP;
71019767226d8e6a1adaa33beb9f517ef40dddfa460cDmitry Shmidt
71026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	switch (oper) {
71036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case TDLS_DISCOVERY_REQ:
71046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl80211_oper = NL80211_TDLS_DISCOVERY_REQ;
71056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		break;
71066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case TDLS_SETUP:
71076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl80211_oper = NL80211_TDLS_SETUP;
71086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		break;
71096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case TDLS_TEARDOWN:
71106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl80211_oper = NL80211_TDLS_TEARDOWN;
71116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		break;
71126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case TDLS_ENABLE_LINK:
71136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl80211_oper = NL80211_TDLS_ENABLE_LINK;
71146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		break;
71156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case TDLS_DISABLE_LINK:
71166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl80211_oper = NL80211_TDLS_DISABLE_LINK;
71176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		break;
71186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case TDLS_ENABLE:
71196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return 0;
71206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case TDLS_DISABLE:
71216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return 0;
71226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	default:
71236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -EINVAL;
71246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
7125b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
71266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_OPER)) ||
71276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper) ||
71286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) {
71296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
71306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
71316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
7132b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
71336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
71346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
7135b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
7136b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
71376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int
71386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtnl80211_tdls_enable_channel_switch(void *priv, const u8 *addr, u8 oper_class,
71396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   const struct hostapd_freq_params *params)
71406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
71416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
71426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
71436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
71446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret = -ENOBUFS;
7145b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
71466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
71476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
71486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -EOPNOTSUPP;
7149b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
71506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Enable TDLS channel switch " MACSTR
71516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   " oper_class=%u freq=%u",
71526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   MAC2STR(addr), oper_class, params->freq);
71536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CHANNEL_SWITCH);
71546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg ||
71556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
71566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u8(msg, NL80211_ATTR_OPER_CLASS, oper_class) ||
71576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (ret = nl80211_put_freq_params(msg, params))) {
71586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
71596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Could not build TDLS chan switch");
71606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return ret;
7161b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	}
7162b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
71636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
7164b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt}
7165b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
7166b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
71676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int
71686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtnl80211_tdls_disable_channel_switch(void *priv, const u8 *addr)
7169b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{
7170b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	struct i802_bss *bss = priv;
7171b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
7172b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	struct nl_msg *msg;
7173b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
71746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
71756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
71766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -EOPNOTSUPP;
7177b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
71786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Disable TDLS channel switch " MACSTR,
71796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   MAC2STR(addr));
71806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH);
71816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg ||
71826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
71836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
71846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
71856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Could not build TDLS cancel chan switch");
71866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
71876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
7188b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
71896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
71906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
7191b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
71926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG TDLS */
7193b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
7194b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
71956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int driver_nl80211_set_key(const char *ifname, void *priv,
71966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  enum wpa_alg alg, const u8 *addr,
71976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  int key_idx, int set_tx,
71986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  const u8 *seq, size_t seq_len,
71996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  const u8 *key, size_t key_len)
72006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
72016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
72026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return wpa_driver_nl80211_set_key(ifname, bss, alg, addr, key_idx,
72036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  set_tx, seq, seq_len, key, key_len);
72046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
7205b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
7206b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
72076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int driver_nl80211_scan2(void *priv,
72086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				struct wpa_driver_scan_params *params)
72096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
72106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
72116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return wpa_driver_nl80211_scan(bss, params);
72126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
7213b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
7214b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
72156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int driver_nl80211_deauthenticate(void *priv, const u8 *addr,
72166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					 int reason_code)
72176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
72186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
72196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return wpa_driver_nl80211_deauthenticate(bss, addr, reason_code);
7220b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt}
7221b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
7222b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
72236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int driver_nl80211_authenticate(void *priv,
72246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				       struct wpa_driver_auth_params *params)
72251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
72261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct i802_bss *bss = priv;
72276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return wpa_driver_nl80211_authenticate(bss, params);
72286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
72291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
72301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
72316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic void driver_nl80211_deinit(void *priv)
72326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
72336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
72346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_driver_nl80211_deinit(bss);
72356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
72361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
72371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
72386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
72396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				    const char *ifname)
72406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
72416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
72426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return wpa_driver_nl80211_if_remove(bss, type, ifname);
72436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
72441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
72451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
72466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int driver_nl80211_send_mlme(void *priv, const u8 *data,
7247a3dc30964aa24aea2b518246f6812663a1103490Dmitry Shmidt				    size_t data_len, int noack,
7248a3dc30964aa24aea2b518246f6812663a1103490Dmitry Shmidt				    unsigned int freq)
72496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
72506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
72516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
7252a3dc30964aa24aea2b518246f6812663a1103490Dmitry Shmidt					    freq, 0, 0, 0);
72536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
72541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
72556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
72566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int driver_nl80211_sta_remove(void *priv, const u8 *addr)
72576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
72586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
72596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return wpa_driver_nl80211_sta_remove(bss, addr, -1, 0);
72601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
72611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
72621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
72636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int driver_nl80211_set_sta_vlan(void *priv, const u8 *addr,
72646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				       const char *ifname, int vlan_id)
72651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
72666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
72676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return i802_set_sta_vlan(bss, addr, ifname, vlan_id);
72686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
72691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
72701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
72716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int driver_nl80211_read_sta_data(void *priv,
72726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					struct hostap_sta_driver_data *data,
72736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					const u8 *addr)
72746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
72756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
72766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return i802_read_sta_data(bss, data, addr);
72776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
72781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
72791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
72806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int driver_nl80211_send_action(void *priv, unsigned int freq,
72816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				      unsigned int wait_time,
72826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				      const u8 *dst, const u8 *src,
72836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				      const u8 *bssid,
72846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				      const u8 *data, size_t data_len,
72856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				      int no_cck)
72866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
72876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
72886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return wpa_driver_nl80211_send_action(bss, freq, wait_time, dst, src,
72896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					      bssid, data, data_len, no_cck);
72906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
72911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
72926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
72936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int driver_nl80211_probe_req_report(void *priv, int report)
72946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
72956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
72966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return wpa_driver_nl80211_probe_req_report(bss, report);
72971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
72981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
72996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
73006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_nl80211_update_ft_ies(void *priv, const u8 *md,
73016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					    const u8 *ies, size_t ies_len)
73021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
73036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
73046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
73051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct i802_bss *bss = priv;
73061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
73076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	u16 mdid = WPA_GET_LE16(md);
73081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Updating FT IEs");
73106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_FT_IES)) ||
73116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_IE, ies_len, ies) ||
73126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u16(msg, NL80211_ATTR_MDID, mdid)) {
73136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
73146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
73151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
73161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
73186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret) {
73196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: update_ft_ies failed "
73206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "err=%d (%s)", ret, strerror(-ret));
73216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
73221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
73241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
73251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtconst u8 * wpa_driver_nl80211_get_macaddr(void *priv)
73281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
73296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
73306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
73311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE)
73336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NULL;
73341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return bss->addr;
73361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
73371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic const char * scan_state_str(enum scan_states scan_state)
73401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
73416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	switch (scan_state) {
73426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case NO_SCAN:
73436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return "NO_SCAN";
73446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case SCAN_REQUESTED:
73456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return "SCAN_REQUESTED";
73466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case SCAN_STARTED:
73476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return "SCAN_STARTED";
73486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case SCAN_COMPLETED:
73496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return "SCAN_COMPLETED";
73506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case SCAN_ABORTED:
73516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return "SCAN_ABORTED";
73526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case SCHED_SCAN_STARTED:
73536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return "SCHED_SCAN_STARTED";
73546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case SCHED_SCAN_STOPPED:
73556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return "SCHED_SCAN_STOPPED";
73566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case SCHED_SCAN_RESULTS:
73576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return "SCHED_SCAN_RESULTS";
7358292b0c3a742226c295f8db76eaef9e90c90e7513Dmitry Shmidt	}
73591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return "??";
73611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
73621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
7365ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt{
7366ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	struct i802_bss *bss = priv;
7367ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
73686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int res;
73696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	char *pos, *end;
7370ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
73716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	pos = buf;
73726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	end = buf + buflen;
7373051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt
73746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	res = os_snprintf(pos, end - pos,
73756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "ifindex=%d\n"
73766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "ifname=%s\n"
73776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "brname=%s\n"
73786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "addr=" MACSTR "\n"
73796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "freq=%d\n"
73806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "%s%s%s%s%s",
73816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  bss->ifindex,
73826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  bss->ifname,
73836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  bss->brname,
73846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  MAC2STR(bss->addr),
73856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  bss->freq,
73866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  bss->beacon_set ? "beacon_set=1\n" : "",
73876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  bss->added_if_into_bridge ?
73886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "added_if_into_bridge=1\n" : "",
73896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  bss->added_bridge ? "added_bridge=1\n" : "",
73906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  bss->in_deinit ? "in_deinit=1\n" : "",
73916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  bss->if_dynamic ? "if_dynamic=1\n" : "");
73926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (os_snprintf_error(end - pos, res))
73936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return pos - buf;
73946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	pos += res;
7395ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
73966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss->wdev_id_set) {
73976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		res = os_snprintf(pos, end - pos, "wdev_id=%llu\n",
73986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  (unsigned long long) bss->wdev_id);
73996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (os_snprintf_error(end - pos, res))
74006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return pos - buf;
74016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		pos += res;
74026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
7403ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
74046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	res = os_snprintf(pos, end - pos,
74056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "phyname=%s\n"
74066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "perm_addr=" MACSTR "\n"
74076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "drv_ifindex=%d\n"
74086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "operstate=%d\n"
74096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "scan_state=%s\n"
74106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "auth_bssid=" MACSTR "\n"
74116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "auth_attempt_bssid=" MACSTR "\n"
74126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "bssid=" MACSTR "\n"
74136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "prev_bssid=" MACSTR "\n"
74146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "associated=%d\n"
74156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "assoc_freq=%u\n"
74166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "monitor_sock=%d\n"
74176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "monitor_ifidx=%d\n"
74186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "monitor_refcount=%d\n"
74196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "last_mgmt_freq=%u\n"
74206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "eapol_tx_sock=%d\n"
74216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "%s%s%s%s%s%s%s%s%s%s%s%s%s",
74226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->phyname,
74236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  MAC2STR(drv->perm_addr),
74246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->ifindex,
74256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->operstate,
74266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  scan_state_str(drv->scan_state),
74276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  MAC2STR(drv->auth_bssid),
74286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  MAC2STR(drv->auth_attempt_bssid),
74296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  MAC2STR(drv->bssid),
74306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  MAC2STR(drv->prev_bssid),
74316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->associated,
74326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->assoc_freq,
74336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->monitor_sock,
74346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->monitor_ifidx,
74356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->monitor_refcount,
74366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->last_mgmt_freq,
74376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->eapol_tx_sock,
74386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->ignore_if_down_event ?
74396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "ignore_if_down_event=1\n" : "",
74406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->scan_complete_events ?
74416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "scan_complete_events=1\n" : "",
74426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->disabled_11b_rates ?
74436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "disabled_11b_rates=1\n" : "",
74446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->pending_remain_on_chan ?
74456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "pending_remain_on_chan=1\n" : "",
74466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->in_interface_list ? "in_interface_list=1\n" : "",
74476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->device_ap_sme ? "device_ap_sme=1\n" : "",
74486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->poll_command_supported ?
74496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "poll_command_supported=1\n" : "",
74506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->data_tx_status ? "data_tx_status=1\n" : "",
74516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->scan_for_auth ? "scan_for_auth=1\n" : "",
74526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->retry_auth ? "retry_auth=1\n" : "",
74536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->use_monitor ? "use_monitor=1\n" : "",
74546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->ignore_next_local_disconnect ?
74556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "ignore_next_local_disconnect=1\n" : "",
74566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  drv->ignore_next_local_deauth ?
74576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  "ignore_next_local_deauth=1\n" : "");
74586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (os_snprintf_error(end - pos, res))
74596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return pos - buf;
74606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	pos += res;
7461ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
74626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (drv->has_capability) {
74636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		res = os_snprintf(pos, end - pos,
74646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  "capa.key_mgmt=0x%x\n"
74656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  "capa.enc=0x%x\n"
74666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  "capa.auth=0x%x\n"
74676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  "capa.flags=0x%llx\n"
74686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  "capa.rrm_flags=0x%x\n"
74696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  "capa.max_scan_ssids=%d\n"
74706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  "capa.max_sched_scan_ssids=%d\n"
74716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  "capa.sched_scan_supported=%d\n"
74726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  "capa.max_match_sets=%d\n"
74736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  "capa.max_remain_on_chan=%u\n"
74746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  "capa.max_stations=%u\n"
74756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  "capa.probe_resp_offloads=0x%x\n"
74766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  "capa.max_acl_mac_addrs=%u\n"
74776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  "capa.num_multichan_concurrent=%u\n"
74786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  "capa.mac_addr_rand_sched_scan_supported=%d\n"
74796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  "capa.mac_addr_rand_scan_supported=%d\n",
74806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  drv->capa.key_mgmt,
74816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  drv->capa.enc,
74826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  drv->capa.auth,
74836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  (unsigned long long) drv->capa.flags,
74846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  drv->capa.rrm_flags,
74856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  drv->capa.max_scan_ssids,
74866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  drv->capa.max_sched_scan_ssids,
74876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  drv->capa.sched_scan_supported,
74886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  drv->capa.max_match_sets,
74896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  drv->capa.max_remain_on_chan,
74906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  drv->capa.max_stations,
74916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  drv->capa.probe_resp_offloads,
74926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  drv->capa.max_acl_mac_addrs,
74936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  drv->capa.num_multichan_concurrent,
74946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  drv->capa.mac_addr_rand_sched_scan_supported,
74956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				  drv->capa.mac_addr_rand_scan_supported);
74966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (os_snprintf_error(end - pos, res))
74976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return pos - buf;
74986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		pos += res;
74996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
7500ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
75016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return pos - buf;
7502ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt}
7503ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
75041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
75056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int set_beacon_data(struct nl_msg *msg, struct beacon_data *settings)
75061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
75076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if ((settings->head &&
75086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put(msg, NL80211_ATTR_BEACON_HEAD,
75096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		     settings->head_len, settings->head)) ||
75106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (settings->tail &&
75116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put(msg, NL80211_ATTR_BEACON_TAIL,
75126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		     settings->tail_len, settings->tail)) ||
75136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (settings->beacon_ies &&
75146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put(msg, NL80211_ATTR_IE,
75156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		     settings->beacon_ies_len, settings->beacon_ies)) ||
75166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (settings->proberesp_ies &&
75176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put(msg, NL80211_ATTR_IE_PROBE_RESP,
75186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		     settings->proberesp_ies_len, settings->proberesp_ies)) ||
75196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (settings->assocresp_ies &&
75206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put(msg, NL80211_ATTR_IE_ASSOC_RESP,
75216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		     settings->assocresp_ies_len, settings->assocresp_ies)) ||
75226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (settings->probe_resp &&
75236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put(msg, NL80211_ATTR_PROBE_RESP,
75246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		     settings->probe_resp_len, settings->probe_resp)))
75256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
75261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
75276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 0;
75281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
75291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
75301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
75316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_switch_channel(void *priv, struct csa_settings *settings)
75321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
75336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
75341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct i802_bss *bss = priv;
75351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
75366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *beacon_csa;
75376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret = -ENOBUFS;
75381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
75396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Channel switch request (cs_count=%u block_tx=%u freq=%d width=%d cf1=%d cf2=%d)",
75406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   settings->cs_count, settings->block_tx,
75416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   settings->freq_params.freq, settings->freq_params.bandwidth,
75426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   settings->freq_params.center_freq1,
75436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   settings->freq_params.center_freq2);
75441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
75456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_AP_CSA)) {
75466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Driver does not support channel switch command");
75476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -EOPNOTSUPP;
75481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
75491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
75506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if ((drv->nlmode != NL80211_IFTYPE_AP) &&
75516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (drv->nlmode != NL80211_IFTYPE_P2P_GO))
75526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -EOPNOTSUPP;
75531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
75546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* check settings validity */
75556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!settings->beacon_csa.tail ||
75566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    ((settings->beacon_csa.tail_len <=
75576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	      settings->counter_offset_beacon) ||
75586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     (settings->beacon_csa.tail[settings->counter_offset_beacon] !=
75596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	      settings->cs_count)))
75606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -EINVAL;
75611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
75626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (settings->beacon_csa.probe_resp &&
75636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    ((settings->beacon_csa.probe_resp_len <=
75646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	      settings->counter_offset_presp) ||
75656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     (settings->beacon_csa.probe_resp[settings->counter_offset_presp] !=
75666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	      settings->cs_count)))
75676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -EINVAL;
75681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
75696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CHANNEL_SWITCH)) ||
75706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT,
75716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			settings->cs_count) ||
75726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (ret = nl80211_put_freq_params(msg, &settings->freq_params)) ||
75736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (settings->block_tx &&
75746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX)))
75756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto error;
75761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
75776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* beacon_after params */
75786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = set_beacon_data(msg, &settings->beacon_after);
75796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret)
75806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto error;
75811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
75826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* beacon_csa params */
75836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	beacon_csa = nla_nest_start(msg, NL80211_ATTR_CSA_IES);
75846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!beacon_csa)
75856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
75861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
75876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = set_beacon_data(msg, &settings->beacon_csa);
75886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret)
75896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto error;
75901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
75916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nla_put_u16(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
75926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			settings->counter_offset_beacon) ||
75936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (settings->beacon_csa.probe_resp &&
75946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_u16(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
75956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			 settings->counter_offset_presp)))
75966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
75971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
75986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nla_nest_end(msg, beacon_csa);
75996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
76006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret) {
76016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: switch_channel failed err=%d (%s)",
76026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   ret, strerror(-ret));
76031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
76046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
76056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
76066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
76076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = -ENOBUFS;
76086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidterror:
76096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nlmsg_free(msg);
76106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Could not build channel switch request");
76116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
76121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
76131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
76141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
76156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_add_ts(void *priv, u8 tsid, const u8 *addr,
76166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			  u8 user_priority, u16 admitted_time)
76171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
76186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
76191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
76206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
76211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int ret;
76221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
76236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG,
76246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   "nl80211: add_ts request: tsid=%u admitted_time=%u up=%d",
76256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   tsid, admitted_time, user_priority);
76261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
76276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!is_sta_interface(drv->nlmode))
76286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOTSUP;
76291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
76306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ADD_TX_TS);
76316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!msg ||
76326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u8(msg, NL80211_ATTR_TSID, tsid) ||
76336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
76346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u8(msg, NL80211_ATTR_USER_PRIO, user_priority) ||
76356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u16(msg, NL80211_ATTR_ADMITTED_TIME, admitted_time)) {
76366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
76376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
76381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
76391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
76406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
76416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret)
76426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: add_ts failed err=%d (%s)",
76436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   ret, strerror(-ret));
76446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
76451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
76461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
76471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
76486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_del_ts(void *priv, u8 tsid, const u8 *addr)
76491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
76506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
76511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
76526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
76536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
76541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
76556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: del_ts request: tsid=%u", tsid);
76561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
76576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!is_sta_interface(drv->nlmode))
76586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOTSUP;
76591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
76606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_TX_TS)) ||
76616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u8(msg, NL80211_ATTR_TSID, tsid) ||
76626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
76636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
76646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
76656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
76661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
76676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
76686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret)
76696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: del_ts failed err=%d (%s)",
76706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   ret, strerror(-ret));
76716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
76724b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
76734b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
76744b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
76756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_TESTING_OPTIONS
76766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int cmd_reply_handler(struct nl_msg *msg, void *arg)
76774b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
76786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
76796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpabuf *buf = arg;
76804b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
76816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!buf)
76826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
76834b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
76846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if ((size_t) genlmsg_attrlen(gnlh, 0) > wpabuf_tailroom(buf)) {
76856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_INFO, "nl80211: insufficient buffer space for reply");
76866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
76876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
76884b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
76896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpabuf_put_data(buf, genlmsg_attrdata(gnlh, 0),
76906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			genlmsg_attrlen(gnlh, 0));
76914b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
76926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return NL_SKIP;
76934b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
76946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_TESTING_OPTIONS */
76954b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
76964b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
76976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int vendor_reply_handler(struct nl_msg *msg, void *arg)
76984b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
76996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
77006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *nl_vendor_reply, *nl;
77016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
77026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpabuf *buf = arg;
77036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int rem;
77044b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
77056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!buf)
77066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
77074b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
77086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
77096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
77106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl_vendor_reply = tb[NL80211_ATTR_VENDOR_DATA];
77114b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
77126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!nl_vendor_reply)
77136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
77144b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
77156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if ((size_t) nla_len(nl_vendor_reply) > wpabuf_tailroom(buf)) {
77166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_INFO, "nl80211: Vendor command: insufficient buffer space for reply");
77176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return NL_SKIP;
77186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
77194b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
77206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nla_for_each_nested(nl, nl_vendor_reply, rem) {
77216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpabuf_put_data(buf, nla_data(nl), nla_len(nl));
77226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
77234b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
77246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return NL_SKIP;
77254b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
77264b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
77274b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
77286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_vendor_cmd(void *priv, unsigned int vendor_id,
77296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			      unsigned int subcmd, const u8 *data,
77306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			      size_t data_len, struct wpabuf *buf)
77314b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
77324b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct i802_bss *bss = priv;
77336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
77346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
77356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
77364b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
77376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_TESTING_OPTIONS
77386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (vendor_id == 0xffffffff) {
77396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		msg = nlmsg_alloc();
77406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (!msg)
77416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -ENOMEM;
77424b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
77436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl80211_cmd(drv, msg, 0, subcmd);
77446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nlmsg_append(msg, (void *) data, data_len, NLMSG_ALIGNTO) <
77456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    0)
77466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
77476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		ret = send_and_recv_msgs(drv, msg, cmd_reply_handler, buf);
77486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (ret)
77496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: command failed err=%d",
77506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   ret);
77516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return ret;
77526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
77536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_TESTING_OPTIONS */
77544b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
77556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_VENDOR)) ||
77566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, vendor_id) ||
77576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, subcmd) ||
77586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (data &&
77596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put(msg, NL80211_ATTR_VENDOR_DATA, data_len, data)))
77606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
77614b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
77626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, vendor_reply_handler, buf);
77636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret)
77646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: vendor command failed err=%d",
77656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   ret);
77666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
77674b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
77686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
77696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nlmsg_free(msg);
77706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return -ENOBUFS;
77714b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
77724b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
77734b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
77746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_set_qos_map(void *priv, const u8 *qos_map_set,
77756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			       u8 qos_map_set_len)
7776700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt{
7777700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	struct i802_bss *bss = priv;
7778700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
77796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
77806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
7781700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
77826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map",
77836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    qos_map_set, qos_map_set_len);
7784700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
77856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_QOS_MAP)) ||
77866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set)) {
77876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
77886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
77896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
7790700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
7791700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
77926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret)
77936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Setting QoS Map failed");
7794700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
7795700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	return ret;
7796700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt}
7797700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
7798700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
77996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_set_wowlan(void *priv,
78006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			      const struct wowlan_triggers *triggers)
780134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
780234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct i802_bss *bss = priv;
780334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
78046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
78056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *wowlan_triggers;
78066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
780734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
78086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan");
780934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
7810a3dc30964aa24aea2b518246f6812663a1103490Dmitry Shmidt	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_SET_WOWLAN)) ||
78116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    !(wowlan_triggers = nla_nest_start(msg,
78126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					       NL80211_ATTR_WOWLAN_TRIGGERS)) ||
78136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (triggers->any &&
78146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
78156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (triggers->disconnect &&
78166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
78176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (triggers->magic_pkt &&
78186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
78196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (triggers->gtk_rekey_failure &&
78206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
78216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (triggers->eap_identity_req &&
78226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
78236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (triggers->four_way_handshake &&
78246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
78256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (triggers->rfkill_release &&
78266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) {
78276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
78286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
78296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
783034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
78316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nla_nest_end(msg, wowlan_triggers);
783234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
78336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
78346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret)
78356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan failed");
78365605286c30e1701491bd3af974ae423727750eddDmitry Shmidt
78376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
78385605286c30e1701491bd3af974ae423727750eddDmitry Shmidt}
78395605286c30e1701491bd3af974ae423727750eddDmitry Shmidt
78405605286c30e1701491bd3af974ae423727750eddDmitry Shmidt
78416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_roaming(void *priv, int allowed, const u8 *bssid)
78425605286c30e1701491bd3af974ae423727750eddDmitry Shmidt{
78435605286c30e1701491bd3af974ae423727750eddDmitry Shmidt	struct i802_bss *bss = priv;
78445605286c30e1701491bd3af974ae423727750eddDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
78456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
78466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *params;
78475605286c30e1701491bd3af974ae423727750eddDmitry Shmidt
78486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Roaming policy: allowed=%d", allowed);
78495605286c30e1701491bd3af974ae423727750eddDmitry Shmidt
78506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!drv->roaming_vendor_cmd_avail) {
78516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
78526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Ignore roaming policy change since driver does not provide command for setting it");
78536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
78545605286c30e1701491bd3af974ae423727750eddDmitry Shmidt	}
78555605286c30e1701491bd3af974ae423727750eddDmitry Shmidt
78566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
78576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
78586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
78596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			QCA_NL80211_VENDOR_SUBCMD_ROAMING) ||
78606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
78616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY,
78626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			allowed ? QCA_ROAMING_ALLOWED_WITHIN_ESS :
78636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			QCA_ROAMING_NOT_ALLOWED) ||
78646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (bssid &&
78656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put(msg, QCA_WLAN_VENDOR_ATTR_MAC_ADDR, ETH_ALEN, bssid))) {
78666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
78676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
78685605286c30e1701491bd3af974ae423727750eddDmitry Shmidt	}
78696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nla_nest_end(msg, params);
78705605286c30e1701491bd3af974ae423727750eddDmitry Shmidt
78716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
78725605286c30e1701491bd3af974ae423727750eddDmitry Shmidt}
78735605286c30e1701491bd3af974ae423727750eddDmitry Shmidt
78745605286c30e1701491bd3af974ae423727750eddDmitry Shmidt
78756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int nl80211_set_mac_addr(void *priv, const u8 *addr)
7876e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt{
78776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
78786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
78796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int new_addr = addr != NULL;
7880e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
78816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!addr)
78826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		addr = drv->perm_addr;
7883e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
78846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) < 0)
78856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
7886e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
78876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, addr) < 0)
78886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	{
78896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
78906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: failed to set_mac_addr for %s to " MACSTR,
78916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   bss->ifname, MAC2STR(addr));
78926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
78936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					  1) < 0) {
78946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			wpa_printf(MSG_DEBUG,
78956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				   "nl80211: Could not restore interface UP after failed set_mac_addr");
78966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		}
78976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
78986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
7899e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
79006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: set_mac_addr for %s to " MACSTR,
79016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		   bss->ifname, MAC2STR(addr));
79026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	drv->addr_changed = new_addr;
79036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_memcpy(bss->addr, addr, ETH_ALEN);
7904e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
79056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1) < 0)
79066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	{
79076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
79086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Could not restore interface UP after set_mac_addr");
79096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
7910e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
7911e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt	return 0;
79126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
7913e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
79146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
79156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_MESH
79166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
79176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_nl80211_init_mesh(void *priv)
79186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
79196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_MESH_POINT)) {
79206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_INFO,
79216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Failed to set interface into mesh mode");
79226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
79236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
79246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 0;
7925e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt}
7926e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
7927e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
7928ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidtstatic int nl80211_put_mesh_id(struct nl_msg *msg, const u8 *mesh_id,
7929ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt			       size_t mesh_id_len)
7930ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt{
7931ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (mesh_id) {
7932ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG, "  * Mesh ID (SSID)",
7933ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt				  mesh_id, mesh_id_len);
7934ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt		return nla_put(msg, NL80211_ATTR_MESH_ID, mesh_id_len, mesh_id);
7935ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	}
7936ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
7937ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	return 0;
7938ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt}
7939ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
7940ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt
79417f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidtstatic int nl80211_join_mesh(struct i802_bss *bss,
79426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			     struct wpa_driver_mesh_join_params *params)
7943e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt{
7944e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
79456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
79466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *container;
79472f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	int ret = -1;
7948e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
79496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: mesh join (ifindex=%d)", drv->ifindex);
79506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_MESH);
7951ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	if (!msg ||
7952ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	    nl80211_put_freq_params(msg, &params->freq) ||
7953ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	    nl80211_put_basic_rates(msg, params->basic_rates) ||
7954ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	    nl80211_put_mesh_id(msg, params->meshid, params->meshid_len) ||
7955ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	    nl80211_put_beacon_int(msg, params->beacon_int))
79566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
7957e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
79586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "  * flags=%08X", params->flags);
7959e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
79606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
79616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!container)
79626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
79636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
79646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->ies) {
79656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "  * IEs", params->ies, params->ie_len);
79666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put(msg, NL80211_MESH_SETUP_IE, params->ie_len,
79676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			    params->ies))
79686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
79696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
79706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* WPA_DRIVER_MESH_FLAG_OPEN_AUTH is treated as default by nl80211 */
79716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (params->flags & WPA_DRIVER_MESH_FLAG_SAE_AUTH) {
79726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (nla_put_u8(msg, NL80211_MESH_SETUP_AUTH_PROTOCOL, 0x1) ||
79736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_AUTH))
79746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			goto fail;
79756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
79766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if ((params->flags & WPA_DRIVER_MESH_FLAG_AMPE) &&
79776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_AMPE))
79786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
79796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if ((params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM) &&
79806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_MPM))
79816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
79826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nla_nest_end(msg, container);
7983e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
79846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
79856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!container)
79866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
7987e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
79886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(params->conf.flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
79896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, 0))
79906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
79916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if ((params->conf.flags & WPA_DRIVER_MESH_FLAG_DRIVER_MPM) &&
79926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
79936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			params->max_peer_links))
79946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
79952f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
79962f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	/*
79972f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	 * Set NL80211_MESHCONF_PLINK_TIMEOUT even if user mpm is used because
79982f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	 * the timer could disconnect stations even in that case.
79992f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	 */
80007f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	if (nla_put_u32(msg, NL80211_MESHCONF_PLINK_TIMEOUT,
80017f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt			params->conf.peer_link_timeout)) {
80022f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to set PLINK_TIMEOUT");
80032f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		goto fail;
80042f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	}
80052f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
80066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nla_nest_end(msg, container);
8007e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
8008e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
80096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = NULL;
8010e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt	if (ret) {
80116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)",
8012e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt			   ret, strerror(-ret));
80136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto fail;
8014e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt	}
80156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = 0;
8016ff787d557db719adea0fdf2679667500c65cf74dDmitry Shmidt	bss->freq = params->freq.freq;
80176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully");
8018e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
80196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtfail:
8020e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt	nlmsg_free(msg);
8021e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt	return ret;
8022e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt}
8023e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
8024e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt
80257f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidtstatic int
80267f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidtwpa_driver_nl80211_join_mesh(void *priv,
80277f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt			     struct wpa_driver_mesh_join_params *params)
80287f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt{
80297f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	struct i802_bss *bss = priv;
80307f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	int ret, timeout;
80317f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
80327f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	timeout = params->conf.peer_link_timeout;
80337f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
80347f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	/* Disable kernel inactivity timer */
80357f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	if (params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM)
80367f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		params->conf.peer_link_timeout = 0;
80377f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
80387f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	ret = nl80211_join_mesh(bss, params);
80397f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	if (ret == -EINVAL && params->conf.peer_link_timeout == 0) {
80407f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		wpa_printf(MSG_DEBUG,
80417f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt			   "nl80211: Mesh join retry for peer_link_timeout");
80427f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		/*
80437f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		 * Old kernel does not support setting
80447f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		 * NL80211_MESHCONF_PLINK_TIMEOUT to zero, so set 60 seconds
80457f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		 * into future from peer_link_timeout.
80467f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		 */
80477f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		params->conf.peer_link_timeout = timeout + 60;
80487f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt		ret = nl80211_join_mesh(priv, params);
80497f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	}
80507f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
80517f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	params->conf.peer_link_timeout = timeout;
80527f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt	return ret;
80537f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt}
80547f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
80557f65602d49069f96a7bb44da8bd79ffe8d4c6a98Dmitry Shmidt
80566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_nl80211_leave_mesh(void *priv)
8057a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt{
80586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
80596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
80606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
80616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
8062a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
80636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: mesh leave (ifindex=%d)", drv->ifindex);
80646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_MESH);
80656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
80666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret) {
80676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)",
80686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   ret, strerror(-ret));
80696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else {
80706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
80716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: mesh leave request send successfully");
8072a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt	}
8073a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
80746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (wpa_driver_nl80211_set_mode(drv->first_bss,
80756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					NL80211_IFTYPE_STATION)) {
80766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_INFO,
80776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Failed to set interface into station mode");
80786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
80796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
8080a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt}
8081a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
80826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_MESH */
8083a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
80846c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
80856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_br_add_ip_neigh(void *priv, u8 version,
80866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				      const u8 *ipaddr, int prefixlen,
80876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				      const u8 *addr)
8088a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt{
80896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_LIBNL3_ROUTE
80906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct i802_bss *bss = priv;
80916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
80926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct rtnl_neigh *rn;
80936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_addr *nl_ipaddr = NULL;
80946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_addr *nl_lladdr = NULL;
80956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int family, addrsize;
80966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int res;
8097a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
80986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!ipaddr || prefixlen == 0 || !addr)
80996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -EINVAL;
8100a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
81016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss->br_ifindex == 0) {
81026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
81036c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: bridge must be set before adding an ip neigh to it");
81046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
81056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
8106a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
81076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!drv->rtnl_sk) {
81086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
81096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: nl_sock for NETLINK_ROUTE is not initialized");
81106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
81116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
8112a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
81136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (version == 4) {
81146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		family = AF_INET;
81156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		addrsize = 4;
81166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else if (version == 6) {
81176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		family = AF_INET6;
81186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		addrsize = 16;
81196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else {
81206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -EINVAL;
8121a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt	}
8122a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
81236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	rn = rtnl_neigh_alloc();
81246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (rn == NULL)
81256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOMEM;
81266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
81276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* set the destination ip address for neigh */
81286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
81296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl_ipaddr == NULL) {
81306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
81316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		res = -ENOMEM;
81326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto errout;
81336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
81346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl_addr_set_prefixlen(nl_ipaddr, prefixlen);
81356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	res = rtnl_neigh_set_dst(rn, nl_ipaddr);
81366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (res) {
81376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
81386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: neigh set destination addr failed");
81396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto errout;
8140a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt	}
8141a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
81426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* set the corresponding lladdr for neigh */
81436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl_lladdr = nl_addr_build(AF_BRIDGE, (u8 *) addr, ETH_ALEN);
81446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl_lladdr == NULL) {
81456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: neigh set lladdr failed");
81466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		res = -ENOMEM;
81476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto errout;
81486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
81496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	rtnl_neigh_set_lladdr(rn, nl_lladdr);
81506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
81516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
81526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	rtnl_neigh_set_state(rn, NUD_PERMANENT);
81536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
81546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	res = rtnl_neigh_add(drv->rtnl_sk, rn, NLM_F_CREATE);
81556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (res) {
81566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
81576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Adding bridge ip neigh failed: %s",
81586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   strerror(errno));
81596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
81606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidterrout:
81616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl_lladdr)
81626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl_addr_put(nl_lladdr);
81636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl_ipaddr)
81646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl_addr_put(nl_ipaddr);
81656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (rn)
81666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		rtnl_neigh_put(rn);
81676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return res;
81686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#else /* CONFIG_LIBNL3_ROUTE */
81696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return -1;
81706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_LIBNL3_ROUTE */
8171a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt}
8172a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
8173a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
81746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_br_delete_ip_neigh(void *priv, u8 version,
81756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt					 const u8 *ipaddr)
8176a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt{
81776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_LIBNL3_ROUTE
8178a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt	struct i802_bss *bss = priv;
8179a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
81806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct rtnl_neigh *rn;
81816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_addr *nl_ipaddr;
81826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int family, addrsize;
81836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int res;
8184a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
81856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!ipaddr)
81866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -EINVAL;
8187a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
81886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (version == 4) {
81896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		family = AF_INET;
81906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		addrsize = 4;
81916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else if (version == 6) {
81926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		family = AF_INET6;
81936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		addrsize = 16;
81946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	} else {
81956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -EINVAL;
81966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
81976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
81986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (bss->br_ifindex == 0) {
81996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
82006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: bridge must be set to delete an ip neigh");
82016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
8202a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt	}
8203a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
82046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!drv->rtnl_sk) {
82056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
82066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: nl_sock for NETLINK_ROUTE is not initialized");
82076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
82086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
8209a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
82106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	rn = rtnl_neigh_alloc();
82116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (rn == NULL)
82126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOMEM;
8213a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
82146c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	/* set the destination ip address for neigh */
82156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
82166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl_ipaddr == NULL) {
82176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
82186c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		res = -ENOMEM;
82196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto errout;
82206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
82216c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	res = rtnl_neigh_set_dst(rn, nl_ipaddr);
82226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (res) {
82236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
82246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: neigh set destination addr failed");
82256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		goto errout;
82266c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
82276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
82286c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
82296c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
82306c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	res = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
82316c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (res) {
82326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
82336c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Deleting bridge ip neigh failed: %s",
82346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   strerror(errno));
82356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
82366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidterrout:
82376c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (nl_ipaddr)
82386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nl_addr_put(nl_ipaddr);
82396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (rn)
82406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		rtnl_neigh_put(rn);
82416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return res;
82426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#else /* CONFIG_LIBNL3_ROUTE */
82436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return -1;
82446c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_LIBNL3_ROUTE */
8245a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt}
8246a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
8247a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt
82486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int linux_write_system_file(const char *path, unsigned int val)
8249fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt{
82506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	char buf[50];
82516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int fd, len;
8252fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
82536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	len = os_snprintf(buf, sizeof(buf), "%u\n", val);
82546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (os_snprintf_error(sizeof(buf), len))
82556c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
8256fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
82576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	fd = open(path, O_WRONLY);
82586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (fd < 0)
82596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
8260fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
82616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (write(fd, buf, len) < 0) {
82626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		wpa_printf(MSG_DEBUG,
82636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Failed to write Linux system file: %s with the value of %d",
82646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   path, val);
82656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		close(fd);
82666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
82676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
82686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	close(fd);
8269fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
82706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 0;
82716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
8272fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
8273fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
82746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic const char * drv_br_port_attr_str(enum drv_br_port_attr attr)
82756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
82766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	switch (attr) {
82776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case DRV_BR_PORT_ATTR_PROXYARP:
82784dd28dc25895165566a1c8a9cac7bcd755ff8fe3Dmitry Shmidt		return "proxyarp_wifi";
82796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case DRV_BR_PORT_ATTR_HAIRPIN_MODE:
82806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return "hairpin_mode";
82816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
82826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
82836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return NULL;
8284fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt}
8285fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
8286fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
82876c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_br_port_set_attr(void *priv, enum drv_br_port_attr attr,
82886c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				       unsigned int val)
8289b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt{
8290b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt	struct i802_bss *bss = priv;
82916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	char path[128];
82926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	const char *attr_txt;
8293b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt
82946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	attr_txt = drv_br_port_attr_str(attr);
82956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (attr_txt == NULL)
82966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -EINVAL;
8297b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt
82986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/%s",
82996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    bss->ifname, attr_txt);
8300b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt
83016c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (linux_write_system_file(path, val))
83026c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
8303b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt
83046c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 0;
83056c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
8306b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt
8307b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt
83086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic const char * drv_br_net_param_str(enum drv_br_net_param param)
83096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
83106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	switch (param) {
83116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case DRV_BR_NET_PARAM_GARP_ACCEPT:
83126c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return "arp_accept";
83138347444e0bfb85e4550817fc99903f38ce8f5bccDmitry Shmidt	default:
83148347444e0bfb85e4550817fc99903f38ce8f5bccDmitry Shmidt		return NULL;
83156c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
8316b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt}
8317b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt
8318b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt
83196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param,
83206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt				       unsigned int val)
8321661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt{
8322661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	struct i802_bss *bss = priv;
83236c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	char path[128];
83246c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	const char *param_txt;
83256c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ip_version = 4;
8326661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
83278347444e0bfb85e4550817fc99903f38ce8f5bccDmitry Shmidt	if (param == DRV_BR_MULTICAST_SNOOPING) {
83288347444e0bfb85e4550817fc99903f38ce8f5bccDmitry Shmidt		os_snprintf(path, sizeof(path),
83298347444e0bfb85e4550817fc99903f38ce8f5bccDmitry Shmidt			    "/sys/devices/virtual/net/%s/bridge/multicast_snooping",
83308347444e0bfb85e4550817fc99903f38ce8f5bccDmitry Shmidt			    bss->brname);
83318347444e0bfb85e4550817fc99903f38ce8f5bccDmitry Shmidt		goto set_val;
83328347444e0bfb85e4550817fc99903f38ce8f5bccDmitry Shmidt	}
83338347444e0bfb85e4550817fc99903f38ce8f5bccDmitry Shmidt
83346c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	param_txt = drv_br_net_param_str(param);
83356c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (param_txt == NULL)
83366c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -EINVAL;
8337661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
83386c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	switch (param) {
83396c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		case DRV_BR_NET_PARAM_GARP_ACCEPT:
83406c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			ip_version = 4;
83416c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			break;
83426c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		default:
83436c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			return -EINVAL;
8344661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	}
8345661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
83466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	os_snprintf(path, sizeof(path), "/proc/sys/net/ipv%d/conf/%s/%s",
83476c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		    ip_version, bss->brname, param_txt);
8348661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
83498347444e0bfb85e4550817fc99903f38ce8f5bccDmitry Shmidtset_val:
83506c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (linux_write_system_file(path, val))
83516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
8352661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
83536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return 0;
83546c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
8355661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
8356661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
83576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int hw_mode_to_qca_acs(enum hostapd_hw_mode hw_mode)
83586c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
83596c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	switch (hw_mode) {
83606c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case HOSTAPD_MODE_IEEE80211B:
83616c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return QCA_ACS_MODE_IEEE80211B;
83626c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case HOSTAPD_MODE_IEEE80211G:
83636c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return QCA_ACS_MODE_IEEE80211G;
83646c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case HOSTAPD_MODE_IEEE80211A:
83656c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return QCA_ACS_MODE_IEEE80211A;
83666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case HOSTAPD_MODE_IEEE80211AD:
83676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return QCA_ACS_MODE_IEEE80211AD;
8368b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt	case HOSTAPD_MODE_IEEE80211ANY:
8369b1e52102c211357f585e9ff6d54501e90254326eDmitry Shmidt		return QCA_ACS_MODE_IEEE80211ANY;
83706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	default:
83716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -1;
83726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	}
8373661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt}
8374661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
8375661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
83766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtstatic int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
8377661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt{
8378661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	struct i802_bss *bss = priv;
8379661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
83806c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nl_msg *msg;
83816c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	struct nlattr *data;
83826c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int ret;
83836c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	int mode;
8384661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
83856c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	mode = hw_mode_to_qca_acs(params->hw_mode);
83866c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (mode < 0)
8387661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		return -1;
8388661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
83896c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
83906c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
83916c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
83926c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			QCA_NL80211_VENDOR_SUBCMD_DO_ACS) ||
83936c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
83946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE, mode) ||
83956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (params->ht_enabled &&
83966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	     nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED)) ||
83976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	    (params->ht40_enabled &&
8398dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt	     nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED)) ||
8399dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt	    (params->vht_enabled &&
8400dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt	     nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED)) ||
8401dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt	    nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
8402dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt			params->ch_width) ||
8403dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt	    (params->ch_list_len &&
8404dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt	     nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST, params->ch_list_len,
8405dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt		     params->ch_list))) {
84066c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		nlmsg_free(msg);
84076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return -ENOBUFS;
8408661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	}
84096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	nla_nest_end(msg, data);
8410661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
8411dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt	wpa_printf(MSG_DEBUG,
8412dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt		   "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d CH_LIST_LEN: %u",
8413dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt		   params->hw_mode, params->ht_enabled, params->ht40_enabled,
8414dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt		   params->vht_enabled, params->ch_width, params->ch_list_len);
8415dda10c2afb8378747491ea5d329a1de635d6d58eDmitry Shmidt
84166c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
84176c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (ret) {
8418661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		wpa_printf(MSG_DEBUG,
84196c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   "nl80211: Failed to invoke driver ACS function: %s",
84206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			   strerror(errno));
8421661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	}
84226c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	return ret;
8423661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt}
8424661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
8425661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt
8426e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshistatic int nl80211_set_band(void *priv, enum set_band band)
8427e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi{
8428e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	struct i802_bss *bss = priv;
8429e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	struct wpa_driver_nl80211_data *drv = bss->drv;
8430e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	struct nl_msg *msg;
8431e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	struct nlattr *data;
8432e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	int ret;
8433e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	enum qca_set_band qca_band;
8434e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi
8435e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	if (!drv->setband_vendor_cmd_avail)
8436e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi		return -1;
8437e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi
8438e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	switch (band) {
8439e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	case WPA_SETBAND_AUTO:
8440e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi		qca_band = QCA_SETBAND_AUTO;
8441e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi		break;
8442e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	case WPA_SETBAND_5G:
8443e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi		qca_band = QCA_SETBAND_5G;
8444e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi		break;
8445e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	case WPA_SETBAND_2G:
8446e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi		qca_band = QCA_SETBAND_2G;
8447e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi		break;
8448e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	default:
8449e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi		return -1;
8450e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	}
8451e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi
8452e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
8453e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
8454e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
8455e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi			QCA_NL80211_VENDOR_SUBCMD_SETBAND) ||
8456e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	    !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
8457e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	    nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE, qca_band)) {
8458e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi		nlmsg_free(msg);
8459e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi		return -ENOBUFS;
8460e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	}
8461e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	nla_nest_end(msg, data);
8462e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi
8463e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
8464e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	if (ret) {
8465e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi		wpa_printf(MSG_DEBUG,
8466e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi			   "nl80211: Driver setband function failed: %s",
8467e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi			   strerror(errno));
8468e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	}
8469e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	return ret;
8470e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi}
8471e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi
8472e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi
84738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst struct wpa_driver_ops wpa_driver_nl80211_ops = {
84748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.name = "nl80211",
84758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.desc = "Linux nl80211/cfg80211",
84768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_bssid = wpa_driver_nl80211_get_bssid,
84778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_ssid = wpa_driver_nl80211_get_ssid,
84784b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.set_key = driver_nl80211_set_key,
84794b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.scan2 = driver_nl80211_scan2,
84801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	.sched_scan = wpa_driver_nl80211_sched_scan,
84811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	.stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
84828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_scan_results2 = wpa_driver_nl80211_get_scan_results,
84834b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.deauthenticate = driver_nl80211_deauthenticate,
84844b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.authenticate = driver_nl80211_authenticate,
84858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.associate = wpa_driver_nl80211_associate,
84868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.global_init = nl80211_global_init,
84878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.global_deinit = nl80211_global_deinit,
84888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.init2 = wpa_driver_nl80211_init,
84894b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.deinit = driver_nl80211_deinit,
84908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_capa = wpa_driver_nl80211_get_capa,
84918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_operstate = wpa_driver_nl80211_set_operstate,
84928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_supp_port = wpa_driver_nl80211_set_supp_port,
84938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_country = wpa_driver_nl80211_set_country,
8494cce06667447b5aec83452adb0c15100ada531095Dmitry Shmidt	.get_country = wpa_driver_nl80211_get_country,
84951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	.set_ap = wpa_driver_nl80211_set_ap,
84968bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	.set_acl = wpa_driver_nl80211_set_acl,
84978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.if_add = wpa_driver_nl80211_if_add,
84984b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.if_remove = driver_nl80211_if_remove,
84994b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.send_mlme = driver_nl80211_send_mlme,
85006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	.get_hw_feature_data = nl80211_get_hw_feature_data,
85018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.sta_add = wpa_driver_nl80211_sta_add,
85024b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.sta_remove = driver_nl80211_sta_remove,
85038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
85048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.sta_set_flags = wpa_driver_nl80211_sta_set_flags,
85058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.hapd_init = i802_init,
85068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.hapd_deinit = i802_deinit,
850775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	.set_wds_sta = i802_set_wds_sta,
85088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_seqnum = i802_get_seqnum,
85098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.flush = i802_flush,
85108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_inact_sec = i802_get_inact_sec,
85118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.sta_clear_stats = i802_sta_clear_stats,
85128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_rts = i802_set_rts,
85138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_frag = i802_set_frag,
85148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_tx_queue_params = i802_set_tx_queue_params,
85154b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.set_sta_vlan = driver_nl80211_set_sta_vlan,
85168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.sta_deauth = i802_sta_deauth,
85178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.sta_disassoc = i802_sta_disassoc,
85184b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.read_sta_data = driver_nl80211_read_sta_data,
85198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_freq = i802_set_freq,
85204b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.send_action = driver_nl80211_send_action,
85218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
85228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.remain_on_channel = wpa_driver_nl80211_remain_on_channel,
85238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.cancel_remain_on_channel =
85248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_driver_nl80211_cancel_remain_on_channel,
85254b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.probe_req_report = driver_nl80211_probe_req_report,
85268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.deinit_ap = wpa_driver_nl80211_deinit_ap,
852704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	.deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
85288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.resume = wpa_driver_nl80211_resume,
85298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.signal_monitor = nl80211_signal_monitor,
85308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.signal_poll = nl80211_signal_poll,
85318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.send_frame = nl80211_send_frame,
85328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_param = nl80211_set_param,
85338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_radio_name = nl80211_get_radio_name,
853475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	.add_pmkid = nl80211_add_pmkid,
853575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	.remove_pmkid = nl80211_remove_pmkid,
853675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	.flush_pmkid = nl80211_flush_pmkid,
85371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	.set_rekey_info = nl80211_set_rekey_info,
85381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	.poll_client = nl80211_poll_client,
85391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	.set_p2p_powersave = nl80211_set_p2p_powersave,
8540ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	.start_dfs_cac = nl80211_start_radar_detection,
8541ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	.stop_ap = wpa_driver_nl80211_stop_ap,
85421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef CONFIG_TDLS
85431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	.send_tdls_mgmt = nl80211_send_tdls_mgmt,
85441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	.tdls_oper = nl80211_tdls_oper,
85456c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	.tdls_enable_channel_switch = nl80211_tdls_enable_channel_switch,
85466c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	.tdls_disable_channel_switch = nl80211_tdls_disable_channel_switch,
85471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* CONFIG_TDLS */
8548700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	.update_ft_ies = wpa_driver_nl80211_update_ft_ies,
854934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	.get_mac_addr = wpa_driver_nl80211_get_macaddr,
8550b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	.get_survey = wpa_driver_nl80211_get_survey,
85515605286c30e1701491bd3af974ae423727750eddDmitry Shmidt	.status = wpa_driver_nl80211_status,
8552e0e48dc666fb14a7bb60264ca87463ba7bc1fe0bDmitry Shmidt	.switch_channel = nl80211_switch_channel,
85531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef ANDROID_P2P
85546e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidt	.set_noa = wpa_driver_set_p2p_noa,
85551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	.get_noa = wpa_driver_get_p2p_noa,
85566e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidt	.set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
8557292b0c3a742226c295f8db76eaef9e90c90e7513Dmitry Shmidt#endif /* ANDROID_P2P */
8558738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidt#ifdef ANDROID
85594171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt#ifndef ANDROID_LIB_STUB
8560738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidt	.driver_cmd = wpa_driver_nl80211_driver_cmd,
85614171258d30a612645aa061cede62233b5c58ca2aDmitry Shmidt#endif /* !ANDROID_LIB_STUB */
8562292b0c3a742226c295f8db76eaef9e90c90e7513Dmitry Shmidt#endif /* ANDROID */
8563a38abf9af7bec7e89dbfb39ac7bb77223fe47c72Dmitry Shmidt	.vendor_cmd = nl80211_vendor_cmd,
8564fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	.set_qos_map = nl80211_set_qos_map,
8565b58836ed5520bf4b769f76ef7dcb802af8c900b8Dmitry Shmidt	.set_wowlan = nl80211_set_wowlan,
8566661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	.roaming = nl80211_roaming,
8567661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	.set_mac_addr = nl80211_set_mac_addr,
85686c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#ifdef CONFIG_MESH
85696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	.init_mesh = wpa_driver_nl80211_init_mesh,
85706c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	.join_mesh = wpa_driver_nl80211_join_mesh,
85716c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	.leave_mesh = wpa_driver_nl80211_leave_mesh,
85726c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt#endif /* CONFIG_MESH */
85736c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	.br_add_ip_neigh = wpa_driver_br_add_ip_neigh,
85746c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	.br_delete_ip_neigh = wpa_driver_br_delete_ip_neigh,
85756c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	.br_port_set_attr = wpa_driver_br_port_set_attr,
85766c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	.br_set_net_param = wpa_driver_br_set_net_param,
85776c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	.add_tx_ts = nl80211_add_ts,
85786c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	.del_tx_ts = nl80211_del_ts,
85796c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	.do_acs = wpa_driver_do_acs,
8580e6ccb16448fd0d5cf080fcb534266797855428d6Ravi Joshi	.set_band = nl80211_set_band,
85818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
8582