driver_nl80211.c revision b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Driver interaction with Linux nl80211/cfg80211
3c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * Copyright (c) 2002-2012, 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/ioctl.h>
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <sys/types.h>
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <sys/stat.h>
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <fcntl.h>
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <net/if.h>
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <netlink/genl/genl.h>
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <netlink/genl/family.h>
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <netlink/genl/ctrl.h>
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <linux/rtnetlink.h>
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <netpacket/packet.h>
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <linux/filter.h>
251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include <linux/errqueue.h>
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "nl80211_copy.h"
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eloop.h"
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/list.h"
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_defs.h"
321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "common/ieee802_11_common.h"
331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "l2_packet/l2_packet.h"
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "netlink.h"
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "linux_ioctl.h"
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "radiotap.h"
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "radiotap_iter.h"
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "rfkill.h"
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "driver.h"
40c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifndef SO_WIFI_STATUS
421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt# if defined(__sparc__)
431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#  define SO_WIFI_STATUS	0x0025
441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt# elif defined(__parisc__)
451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#  define SO_WIFI_STATUS	0x4022
461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt# else
471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#  define SO_WIFI_STATUS	41
481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt# endif
491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt# define SCM_WIFI_STATUS	SO_WIFI_STATUS
511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif
521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifndef SO_EE_ORIGIN_TXSTATUS
541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#define SO_EE_ORIGIN_TXSTATUS	4
551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif
561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifndef PACKET_TX_TIMESTAMP
581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#define PACKET_TX_TIMESTAMP	16
591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif
601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef ANDROID
621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#include "android_drv.h"
631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* ANDROID */
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_LIBNL20
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* libnl 2.0 compatibility code */
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define nl_handle nl_sock
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define nl80211_handle_alloc nl_socket_alloc_cb
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define nl80211_handle_destroy nl_socket_free
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * libnl 1.1 has a bug, it tries to allocate socket numbers densely
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * but when you free a socket again it will mess up its bitmap and
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * and use the wrong number the next time it needs a socket ID.
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Therefore, we wrap the handle alloc/destroy and add our own pid
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * accounting.
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic uint32_t port_bitmap[32] = { 0 };
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct nl_handle *nl80211_handle_alloc(void *cb)
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_handle *handle;
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uint32_t pid = getpid() & 0x3FFFFF;
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	handle = nl_handle_alloc_cb(cb);
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < 1024; i++) {
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (port_bitmap[i / 32] & (1 << (i % 32)))
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		port_bitmap[i / 32] |= 1 << (i % 32);
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pid += i << 22;
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_socket_set_local_port(handle, pid);
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return handle;
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_handle_destroy(struct nl_handle *handle)
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uint32_t port = nl_socket_get_local_port(handle);
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	port >>= 22;
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	port_bitmap[port / 32] &= ~(1 << (port % 32));
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_handle_destroy(handle);
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_LIBNL20 */
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg)
1131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
1141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_handle *handle;
1151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	handle = nl80211_handle_alloc(cb);
1171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (handle == NULL) {
1181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
1191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "callbacks (%s)", dbg);
1201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
1211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
1221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (genl_connect(handle)) {
1241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
1251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "netlink (%s)", dbg);
1261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_handle_destroy(handle);
1271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
1281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
1291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return handle;
1311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
1321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nl_destroy_handles(struct nl_handle **handle)
1351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
1361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (*handle == NULL)
1371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
1381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_handle_destroy(*handle);
1391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	*handle = NULL;
1401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
1411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef IFF_LOWER_UP
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define IFF_LOWER_UP   0x10000         /* driver signals L1 up         */
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef IFF_DORMANT
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define IFF_DORMANT    0x20000         /* driver signals dormant       */
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef IF_OPER_DORMANT
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define IF_OPER_DORMANT 5
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef IF_OPER_UP
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define IF_OPER_UP 6
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct nl80211_global {
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct dl_list interfaces;
1591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int if_add_ifindex;
16034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u64 if_add_wdevid;
16134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	int if_add_wdevid_set;
1621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct netlink_data *netlink;
1631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_cb *nl_cb;
1641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_handle *nl;
1651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int nl80211_id;
1661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int ioctl_sock; /* socket for ioctl() use */
1671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_handle *nl_event;
1691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt};
1701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstruct nl80211_wiphy_data {
1721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct dl_list list;
1731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct dl_list bsss;
1741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct dl_list drvs;
1751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_handle *nl_beacons;
1771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_cb *nl_cb;
1781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int wiphy_idx;
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nl80211_global_deinit(void *priv);
1831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct i802_bss {
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv;
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *next;
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifindex;
18834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u64 wdev_id;
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char ifname[IFNAMSIZ + 1];
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char brname[IFNAMSIZ];
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int beacon_set:1;
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int added_if_into_bridge:1;
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int added_bridge:1;
19404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	unsigned int in_deinit:1;
19534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	unsigned int wdev_id_set:1;
1961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u8 addr[ETH_ALEN];
1981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int freq;
200b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	int if_dynamic;
2011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
202a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	void *ctx;
2031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_handle *nl_preq, *nl_mgmt;
2041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_cb *nl_cb;
2051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl80211_wiphy_data *wiphy_data;
2071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct dl_list wiphy_list;
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpa_driver_nl80211_data {
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl80211_global *global;
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct dl_list list;
2131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct dl_list wiphy_list;
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char phyname[32];
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *ctx;
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifindex;
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int if_removed;
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int if_disabled;
2191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int ignore_if_down_event;
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rfkill_data *rfkill;
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_capa capa;
222444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	u8 *extended_capa, *extended_capa_mask;
223444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	unsigned int extended_capa_len;
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int has_capability;
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int operstate;
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int scan_complete_events;
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_cb *nl_cb;
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 auth_bssid[ETH_ALEN];
2338bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	u8 auth_attempt_bssid[ETH_ALEN];
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 bssid[ETH_ALEN];
2358bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	u8 prev_bssid[ETH_ALEN];
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int associated;
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 ssid[32];
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t ssid_len;
2391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	enum nl80211_iftype nlmode;
2401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	enum nl80211_iftype ap_scan_as_station;
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int assoc_freq;
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int monitor_sock;
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int monitor_ifidx;
2451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int monitor_refcount;
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	unsigned int disabled_11b_rates:1;
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int pending_remain_on_chan:1;
2491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	unsigned int in_interface_list:1;
2501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	unsigned int device_ap_sme:1;
2511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	unsigned int poll_command_supported:1;
2521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	unsigned int data_tx_status:1;
2531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	unsigned int scan_for_auth:1;
2541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	unsigned int retry_auth:1;
2551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	unsigned int use_monitor:1;
256d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	unsigned int ignore_next_local_disconnect:1;
25734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	unsigned int allow_p2p_device:1;
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u64 remain_on_chan_cookie;
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u64 send_action_cookie;
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int last_mgmt_freq;
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_scan_filter *filter_ssids;
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t num_filter_ssids;
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss first_bss;
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int eapol_tx_sock;
2701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int eapol_sock; /* socket for EAPOL frames */
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int default_if_indices[16];
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int *if_indices;
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int num_if_indices;
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int last_freq;
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int last_freq_ht;
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
2811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* From failed authentication command */
2831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int auth_freq;
2841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u8 auth_bssid_[ETH_ALEN];
2851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u8 auth_ssid[32];
2861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	size_t auth_ssid_len;
2871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int auth_alg;
2881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u8 *auth_ie;
2891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	size_t auth_ie_len;
2901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u8 auth_wep_key[4][16];
2911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	size_t auth_wep_key_len[4];
2921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int auth_wep_tx_keyidx;
2931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int auth_local_state_change;
2941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int auth_p2p;
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2984b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic void wpa_driver_nl80211_deinit(struct i802_bss *bss);
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    void *timeout_ctx);
3011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
3021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				       enum nl80211_iftype nlmode);
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtwpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   const u8 *addr, int cmd, u16 reason_code,
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   int local_state_change);
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_remove_monitor_interface(
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv);
3101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_send_frame_cmd(struct i802_bss *bss,
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  unsigned int freq, unsigned int wait,
3121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				  const u8 *buf, size_t buf_len, u64 *cookie,
3131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				  int no_cck, int no_ack, int offchanok);
314c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidtstatic int nl80211_register_frame(struct i802_bss *bss,
315c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt				  struct nl_handle *hl_handle,
316c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt				  u16 type, const u8 *match, size_t match_len);
3174b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
3184b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					       int report);
3191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef ANDROID
3201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int android_pno_start(struct i802_bss *bss,
3211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			     struct wpa_driver_scan_params *params);
3221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int android_pno_stop(struct i802_bss *bss);
3231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* ANDROID */
3241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef ANDROID_P2P
3256e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidtint wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
3261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtint wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
3276e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidtint wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow);
3286e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidtint wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
3296e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidt				  const struct wpabuf *proberesp,
3306e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidt				  const struct wpabuf *assocresp);
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
3374b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					enum wpa_driver_if_type type,
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					const char *ifname);
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* HOSTAPD */
3411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic inline void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
3421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
3431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
3441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic inline void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
3461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
3471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
3481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic inline int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
354738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidt#ifdef ANDROID
355738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidtextern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
356738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidt					 size_t buf_len);
357738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidt#endif
358738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidt
3594b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
3604b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt				       struct hostapd_freq_params *freq);
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     int ifindex, int disabled);
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv);
3651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int wpa_driver_nl80211_authenticate_retry(
3661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv);
3671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
368b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic int i802_set_iface_flags(struct i802_bss *bss, int up);
369b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
3701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
37134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic const char * nl80211_command_to_string(enum nl80211_commands cmd)
37234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
37334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt#define C2S(x) case x: return #x;
37434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	switch (cmd) {
37534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_UNSPEC)
37634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_GET_WIPHY)
37734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_WIPHY)
37834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_NEW_WIPHY)
37934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_DEL_WIPHY)
38034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_GET_INTERFACE)
38134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_INTERFACE)
38234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_NEW_INTERFACE)
38334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_DEL_INTERFACE)
38434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_GET_KEY)
38534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_KEY)
38634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_NEW_KEY)
38734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_DEL_KEY)
38834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_GET_BEACON)
38934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_BEACON)
39034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_START_AP)
39134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_STOP_AP)
39234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_GET_STATION)
39334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_STATION)
39434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_NEW_STATION)
39534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_DEL_STATION)
39634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_GET_MPATH)
39734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_MPATH)
39834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_NEW_MPATH)
39934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_DEL_MPATH)
40034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_BSS)
40134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_REG)
40234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_REQ_SET_REG)
40334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_GET_MESH_CONFIG)
40434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_MESH_CONFIG)
40534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_MGMT_EXTRA_IE)
40634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_GET_REG)
40734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_GET_SCAN)
40834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_TRIGGER_SCAN)
40934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_NEW_SCAN_RESULTS)
41034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SCAN_ABORTED)
41134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_REG_CHANGE)
41234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_AUTHENTICATE)
41334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_ASSOCIATE)
41434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_DEAUTHENTICATE)
41534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_DISASSOCIATE)
41634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_MICHAEL_MIC_FAILURE)
41734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_REG_BEACON_HINT)
41834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_JOIN_IBSS)
41934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_LEAVE_IBSS)
42034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_TESTMODE)
42134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_CONNECT)
42234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_ROAM)
42334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_DISCONNECT)
42434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_WIPHY_NETNS)
42534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_GET_SURVEY)
42634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_NEW_SURVEY_RESULTS)
42734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_PMKSA)
42834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_DEL_PMKSA)
42934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_FLUSH_PMKSA)
43034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_REMAIN_ON_CHANNEL)
43134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL)
43234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_TX_BITRATE_MASK)
43334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_REGISTER_FRAME)
43434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_FRAME)
43534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_FRAME_TX_STATUS)
43634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_POWER_SAVE)
43734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_GET_POWER_SAVE)
43834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_CQM)
43934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_NOTIFY_CQM)
44034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_CHANNEL)
44134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_WDS_PEER)
44234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_FRAME_WAIT_CANCEL)
44334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_JOIN_MESH)
44434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_LEAVE_MESH)
44534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_UNPROT_DEAUTHENTICATE)
44634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_UNPROT_DISASSOCIATE)
44734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_NEW_PEER_CANDIDATE)
44834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_GET_WOWLAN)
44934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_WOWLAN)
45034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_START_SCHED_SCAN)
45134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_STOP_SCHED_SCAN)
45234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SCHED_SCAN_RESULTS)
45334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SCHED_SCAN_STOPPED)
45434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_REKEY_OFFLOAD)
45534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_PMKSA_CANDIDATE)
45634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_TDLS_OPER)
45734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_TDLS_MGMT)
45834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_UNEXPECTED_FRAME)
45934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_PROBE_CLIENT)
46034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_REGISTER_BEACONS)
46134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_UNEXPECTED_4ADDR_FRAME)
46234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_NOACK_MAP)
46334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_CH_SWITCH_NOTIFY)
46434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_START_P2P_DEVICE)
46534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_STOP_P2P_DEVICE)
46634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_CONN_FAILED)
46734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_MCAST_RATE)
46834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_SET_MAC_ACL)
46934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_RADAR_DETECT)
47034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_GET_PROTOCOL_FEATURES)
47134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_UPDATE_FT_IES)
47234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_FT_EVENT)
47334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_CRIT_PROTOCOL_START)
47434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	C2S(NL80211_CMD_CRIT_PROTOCOL_STOP)
47534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	default:
47634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return "NL80211_CMD_UNKNOWN";
47734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
47834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt#undef C2S
47934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
48034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
48134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
4821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int is_ap_interface(enum nl80211_iftype nlmode)
4831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
4841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return (nlmode == NL80211_IFTYPE_AP ||
4851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nlmode == NL80211_IFTYPE_P2P_GO);
4861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
4871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int is_sta_interface(enum nl80211_iftype nlmode)
4901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
4911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return (nlmode == NL80211_IFTYPE_STATION ||
4921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nlmode == NL80211_IFTYPE_P2P_CLIENT);
4931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
4941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
4951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
49634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int is_p2p_net_interface(enum nl80211_iftype nlmode)
4971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
4981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return (nlmode == NL80211_IFTYPE_P2P_CLIENT ||
4991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nlmode == NL80211_IFTYPE_P2P_GO);
5001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5038bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidtstatic void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
5048bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt{
5058bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	if (drv->associated)
5068bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
5078bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	drv->associated = 0;
5088bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	os_memset(drv->bssid, 0, ETH_ALEN);
5098bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt}
5108bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
5118bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
51287fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinenstruct nl80211_bss_info_arg {
51387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	struct wpa_driver_nl80211_data *drv;
51487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	struct wpa_scan_results *res;
51587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	unsigned int assoc_freq;
5161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u8 assoc_bssid[ETH_ALEN];
51787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen};
51887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
51987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinenstatic int bss_info_handler(struct nl_msg *msg, void *arg);
52087fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
52187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* nl80211 code */
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ack_handler(struct nl_msg *msg, void *arg)
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int *err = arg;
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*err = 0;
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_STOP;
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int finish_handler(struct nl_msg *msg, void *arg)
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int *ret = arg;
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*ret = 0;
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 void *arg)
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int *ret = arg;
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*ret = err->error;
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int no_seq_check(struct nl_msg *msg, void *arg)
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_OK;
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int send_and_recv(struct nl80211_global *global,
5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 struct nl_handle *nl_handle, struct nl_msg *msg,
5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 int (*valid_handler)(struct nl_msg *, void *),
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 void *valid_data)
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_cb *cb;
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int err = -ENOMEM;
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	cb = nl_cb_clone(global->nl_cb);
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!cb)
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto out;
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	err = nl_send_auto_complete(nl_handle, msg);
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (err < 0)
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto out;
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	err = 1;
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (valid_handler)
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  valid_handler, valid_data);
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (err > 0)
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl_recvmsgs(nl_handle, cb);
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt out:
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cb_put(cb);
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return err;
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int send_and_recv_msgs_global(struct nl80211_global *global,
5881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				     struct nl_msg *msg,
5891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				     int (*valid_handler)(struct nl_msg *, void *),
5901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				     void *valid_data)
5911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
5921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return send_and_recv(global, global->nl, msg, valid_handler,
5931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			     valid_data);
5941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
5951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
59604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
59780da0428ce21beb670d31bd06d025d8609d658b4Jouni Malinen#ifndef ANDROID
59880da0428ce21beb670d31bd06d025d8609d658b4Jouni Malinenstatic
59980da0428ce21beb670d31bd06d025d8609d658b4Jouni Malinen#endif
600738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidtint send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      struct nl_msg *msg,
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      int (*valid_handler)(struct nl_msg *, void *),
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      void *valid_data)
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return send_and_recv(drv->global, drv->global->nl, msg,
6061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			     valid_handler, valid_data);
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct family_data {
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const char *group;
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int id;
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
61734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
61834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (bss->wdev_id_set)
61934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
62034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	else
62134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
62234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return 0;
62334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
62434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtnla_put_failure:
62534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return -1;
62634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
62734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
62834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int family_handler(struct nl_msg *msg, void *arg)
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct family_data *res = arg;
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb[CTRL_ATTR_MAX + 1];
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *mcgrp;
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!tb[CTRL_ATTR_MCAST_GROUPS])
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  nla_len(mcgrp), NULL);
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       res->group,
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl_get_multicast_id(struct nl80211_global *global,
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       const char *family, const char *group)
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct family_data res = { group, -ENOENT };
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
6701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"),
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, 0, CTRL_CMD_GETFAMILY, 0);
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ret = send_and_recv_msgs_global(global, msg, family_handler, &res);
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == 0)
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = res.id;
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
6861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			  struct nl_msg *msg, int flags, uint8_t cmd)
6871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
6881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
6891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   0, flags, cmd, 0);
6901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
6911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstruct wiphy_idx_data {
6941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int wiphy_idx;
69534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	enum nl80211_iftype nlmode;
69634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 *macaddr;
6971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt};
6981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int netdev_info_handler(struct nl_msg *msg, void *arg)
7011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
7021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
7031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
7041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wiphy_idx_data *info = arg;
7051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
7071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
7081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (tb[NL80211_ATTR_WIPHY])
7101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
7111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
71234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (tb[NL80211_ATTR_IFTYPE])
71334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		info->nlmode = nla_get_u32(tb[NL80211_ATTR_IFTYPE]);
71434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
71534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (tb[NL80211_ATTR_MAC] && info->macaddr)
71634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		os_memcpy(info->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
71734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			  ETH_ALEN);
71834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
7191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return NL_SKIP;
7201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
7211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_get_wiphy_index(struct i802_bss *bss)
7241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
7251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_msg *msg;
7261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wiphy_idx_data data = {
7271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		.wiphy_idx = -1,
72834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		.macaddr = NULL,
7291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	};
7301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = nlmsg_alloc();
7321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!msg)
73334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NL80211_IFTYPE_UNSPECIFIED;
7341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
7361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (nl80211_set_iface_id(msg, bss) < 0)
73834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		goto nla_put_failure;
7391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
7411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return data.wiphy_idx;
7421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
7431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtnla_put_failure:
7441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
7451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return -1;
7461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
7471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
74934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic enum nl80211_iftype nl80211_get_ifmode(struct i802_bss *bss)
75034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
75134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct nl_msg *msg;
75234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wiphy_idx_data data = {
75334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		.nlmode = NL80211_IFTYPE_UNSPECIFIED,
75434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		.macaddr = NULL,
75534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	};
75634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
75734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	msg = nlmsg_alloc();
75834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (!msg)
75934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return -1;
76034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
76134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
76234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
76334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (nl80211_set_iface_id(msg, bss) < 0)
76434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		goto nla_put_failure;
76534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
76634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
76734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return data.nlmode;
76834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	msg = NULL;
76934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtnla_put_failure:
77034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	nlmsg_free(msg);
77134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return NL80211_IFTYPE_UNSPECIFIED;
77234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
77334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
77434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
77534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt#ifndef HOSTAPD
77634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int nl80211_get_macaddr(struct i802_bss *bss)
77734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
77834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct nl_msg *msg;
77934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wiphy_idx_data data = {
78034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		.macaddr = bss->addr,
78134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	};
78234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
78334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	msg = nlmsg_alloc();
78434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (!msg)
78534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NL80211_IFTYPE_UNSPECIFIED;
78634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
78734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
78834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (nl80211_set_iface_id(msg, bss) < 0)
78934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		goto nla_put_failure;
79034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
79134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data);
79234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
79334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtnla_put_failure:
79434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	nlmsg_free(msg);
79534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return NL80211_IFTYPE_UNSPECIFIED;
79634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
79734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt#endif /* HOSTAPD */
79834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
79934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
8001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
8011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				    struct nl80211_wiphy_data *w)
8021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
8031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_msg *msg;
8041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int ret = -1;
8051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = nlmsg_alloc();
8071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!msg)
8081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
8091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS);
8111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx);
8131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL);
8151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
8161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ret) {
8171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
8181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "failed: ret=%d (%s)",
8191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   ret, strerror(-ret));
8201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto nla_put_failure;
8211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
8221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ret = 0;
8231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtnla_put_failure:
8241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
8251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return ret;
8261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
8271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
8301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
8311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl80211_wiphy_data *w = eloop_ctx;
8321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
833c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available");
8341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_recvmsgs(handle, w->nl_cb);
8361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
8371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int process_beacon_event(struct nl_msg *msg, void *arg)
8401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
8411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl80211_wiphy_data *w = arg;
8421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv;
8431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
8441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
8451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	union wpa_event_data event;
8461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
8481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
8491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (gnlh->cmd != NL80211_CMD_FRAME) {
8511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Unexpected beacon event? (%d)",
8521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   gnlh->cmd);
8531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NL_SKIP;
8541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
8551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!tb[NL80211_ATTR_FRAME])
8571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NL_SKIP;
8581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_for_each(drv, &w->drvs, struct wpa_driver_nl80211_data,
8601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 wiphy_list) {
8611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		os_memset(&event, 0, sizeof(event));
8621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		event.rx_mgmt.frame = nla_data(tb[NL80211_ATTR_FRAME]);
8631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		event.rx_mgmt.frame_len = nla_len(tb[NL80211_ATTR_FRAME]);
8641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
8651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
8661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return NL_SKIP;
8681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
8691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic struct nl80211_wiphy_data *
8721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtnl80211_get_wiphy_data_ap(struct i802_bss *bss)
8731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
8741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	static DEFINE_DL_LIST(nl80211_wiphys);
8751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl80211_wiphy_data *w;
8761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int wiphy_idx, found = 0;
8771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct i802_bss *tmp_bss;
8781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (bss->wiphy_data != NULL)
8801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return bss->wiphy_data;
8811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wiphy_idx = nl80211_get_wiphy_index(bss);
8831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_for_each(w, &nl80211_wiphys, struct nl80211_wiphy_data, list) {
8851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (w->wiphy_idx == wiphy_idx)
8861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			goto add;
8871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
8881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* alloc new one */
8901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	w = os_zalloc(sizeof(*w));
8911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (w == NULL)
8921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
8931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	w->wiphy_idx = wiphy_idx;
8941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_init(&w->bsss);
8951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_init(&w->drvs);
8961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
8971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
8981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!w->nl_cb) {
8991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		os_free(w);
9001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
9011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
9021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
9031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_beacon_event,
9041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  w);
9051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
9061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
9071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					 "wiphy beacons");
9081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (w->nl_beacons == NULL) {
9091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		os_free(w);
9101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
9111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
9121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
9131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211_register_beacons(bss->drv, w)) {
9141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl_destroy_handles(&w->nl_beacons);
9151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		os_free(w);
9161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
9171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
9181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
9191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	eloop_register_read_sock(nl_socket_get_fd(w->nl_beacons),
9201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				 nl80211_recv_beacons, w, w->nl_beacons);
9211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
9221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_add(&nl80211_wiphys, &w->list);
9231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
9241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtadd:
9251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* drv entry for this bss already there? */
9261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
9271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (tmp_bss->drv == bss->drv) {
9281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			found = 1;
9291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
9301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
9311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
9321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* if not add it */
9331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!found)
9341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		dl_list_add(&w->drvs, &bss->drv->wiphy_list);
9351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
9361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_add(&w->bsss, &bss->wiphy_list);
9371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	bss->wiphy_data = w;
9381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return w;
9391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
9401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
9411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
9421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
9431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
9441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl80211_wiphy_data *w = bss->wiphy_data;
9451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct i802_bss *tmp_bss;
9461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int found = 0;
9471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
9481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (w == NULL)
9491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
9501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	bss->wiphy_data = NULL;
9511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_del(&bss->wiphy_list);
9521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
9531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* still any for this drv present? */
9541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
9551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (tmp_bss->drv == bss->drv) {
9561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			found = 1;
9571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
9581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
9591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
9601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* if not remove it */
9611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!found)
9621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		dl_list_del(&bss->drv->wiphy_list);
9631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
9641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!dl_list_empty(&w->bsss))
9651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
9661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
9671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	eloop_unregister_read_sock(nl_socket_get_fd(w->nl_beacons));
9681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
9691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_cb_put(w->nl_cb);
9701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_destroy_handles(&w->nl_beacons);
9711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_del(&w->list);
9721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_free(w);
9731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
9741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
9751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!drv->associated)
9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(bssid, drv->bssid, ETH_ALEN);
9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!drv->associated)
9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
9938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(ssid, drv->ssid, drv->ssid_len);
9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return drv->ssid_len;
9958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  char *buf, size_t len, int del)
10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
10028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len > sizeof(event.interface_status.ifname))
10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		len = sizeof(event.interface_status.ifname) - 1;
10068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(event.interface_status.ifname, buf, len);
10078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
10088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		EVENT_INTERFACE_ADDED;
10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
10118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   del ? "DEL" : "NEW",
10128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   event.interface_status.ifname,
10138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   del ? "removed" : "added");
10148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) {
101604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (del) {
101704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			if (drv->if_removed) {
101804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				wpa_printf(MSG_DEBUG, "nl80211: if_removed "
101904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					   "already set - ignore event");
102004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				return;
102104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			}
10228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			drv->if_removed = 1;
102304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		} else {
102404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			if (if_nametoindex(drv->first_bss.ifname) == 0) {
102504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				wpa_printf(MSG_DEBUG, "nl80211: Interface %s "
102604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					   "does not exist - ignore "
102704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					   "RTM_NEWLINK",
102804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					   drv->first_bss.ifname);
102904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				return;
103004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			}
103104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			if (!drv->if_removed) {
103204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				wpa_printf(MSG_DEBUG, "nl80211: if_removed "
103304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					   "already cleared - ignore event");
103404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				return;
103504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			}
10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			drv->if_removed = 0;
103704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		}
10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
10458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 u8 *buf, size_t len)
10468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int attrlen, rta_len;
10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rtattr *attr;
10498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	attrlen = len;
10518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	attr = (struct rtattr *) buf;
10528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rta_len = RTA_ALIGN(sizeof(struct rtattr));
10548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (RTA_OK(attr, attrlen)) {
10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (attr->rta_type == IFLA_IFNAME) {
10568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname)
10578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    == 0)
10588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return 1;
10598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else
10608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
10618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
10628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		attr = RTA_NEXT(attr, attrlen);
10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
10668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
10708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  int ifindex, u8 *buf, size_t len)
10718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->ifindex == ifindex)
10738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 1;
10748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
10768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
10778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "interface");
10788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_driver_nl80211_finish_drv_init(drv);
10798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 1;
10808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
10838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic struct wpa_driver_nl80211_data *
10871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtnl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len)
10881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
10891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv;
10901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_for_each(drv, &global->interfaces,
10911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 struct wpa_driver_nl80211_data, list) {
10921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (wpa_driver_nl80211_own_ifindex(drv, idx, buf, len) ||
10931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    have_ifidx(drv, idx))
10941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return drv;
10951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
10961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return NULL;
10971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
10981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
10991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
11008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
11018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 struct ifinfomsg *ifi,
11028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 u8 *buf, size_t len)
11038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl80211_global *global = ctx;
11051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv;
11068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int attrlen, rta_len;
11078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rtattr *attr;
11088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 brid = 0;
11091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	char namebuf[IFNAMSIZ];
11108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
11121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!drv) {
11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign "
11148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "ifindex %d", ifi->ifi_index);
11158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
11168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
11198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "(%s%s%s%s)",
11208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   drv->operstate, ifi->ifi_flags,
11218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
11228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
11238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
11248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
11258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
11271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (if_indextoname(ifi->ifi_index, namebuf) &&
11281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    linux_iface_up(drv->global->ioctl_sock,
11291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   drv->first_bss.ifname) > 0) {
11301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
11311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "event since interface %s is up", namebuf);
11321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return;
11331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
11348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Interface down");
11351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (drv->ignore_if_down_event) {
11361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
11371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "event generated by mode change");
11381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			drv->ignore_if_down_event = 0;
11391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		} else {
11401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			drv->if_disabled = 1;
11411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_supplicant_event(drv->ctx,
11421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					     EVENT_INTERFACE_DISABLED, NULL);
11431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
11448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
11471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (if_indextoname(ifi->ifi_index, namebuf) &&
11481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    linux_iface_up(drv->global->ioctl_sock,
11491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   drv->first_bss.ifname) == 0) {
11501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
11511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "event since interface %s is down",
11521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   namebuf);
115304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		} else if (if_nametoindex(drv->first_bss.ifname) == 0) {
115404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
115504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				   "event since interface %s does not exist",
115604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				   drv->first_bss.ifname);
115704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		} else if (drv->if_removed) {
115804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
115904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				   "event since interface %s is marked "
116004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				   "removed", drv->first_bss.ifname);
11611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		} else {
11621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Interface up");
11631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			drv->if_disabled = 0;
11641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
11651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					     NULL);
11661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
11678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
11708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Some drivers send the association event before the operup event--in
11718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
11728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * fails. This will hit us when wpa_supplicant does not need to do
11738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * IEEE 802.1X authentication
11748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
11758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->operstate == 1 &&
11768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
11778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    !(ifi->ifi_flags & IFF_RUNNING))
11781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
11798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       -1, IF_OPER_UP);
11808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	attrlen = len;
11828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	attr = (struct rtattr *) buf;
11838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rta_len = RTA_ALIGN(sizeof(struct rtattr));
11848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (RTA_OK(attr, attrlen)) {
11858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (attr->rta_type == IFLA_IFNAME) {
11868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_driver_nl80211_event_link(
11878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				drv,
11888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				((char *) attr) + rta_len,
11898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				attr->rta_len - rta_len, 0);
11908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else if (attr->rta_type == IFLA_MASTER)
11918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			brid = nla_get_u32((struct nlattr *) attr);
11928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		attr = RTA_NEXT(attr, attrlen);
11938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ifi->ifi_family == AF_BRIDGE && brid) {
11968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* device has been added to bridge */
11978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if_indextoname(brid, namebuf);
11988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
11998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   brid, namebuf);
12008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		add_ifidx(drv, brid);
12018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
12068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 struct ifinfomsg *ifi,
12078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 u8 *buf, size_t len)
12088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl80211_global *global = ctx;
12101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv;
12118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int attrlen, rta_len;
12128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rtattr *attr;
12138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 brid = 0;
12148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
12161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!drv) {
12171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Ignore dellink event for "
12181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "foreign ifindex %d", ifi->ifi_index);
12191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
12201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
12211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
12228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	attrlen = len;
12238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	attr = (struct rtattr *) buf;
12248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rta_len = RTA_ALIGN(sizeof(struct rtattr));
12268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (RTA_OK(attr, attrlen)) {
12278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (attr->rta_type == IFLA_IFNAME) {
12288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_driver_nl80211_event_link(
12298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				drv,
12308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				((char *) attr) + rta_len,
12318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				attr->rta_len - rta_len, 1);
12328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else if (attr->rta_type == IFLA_MASTER)
12338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			brid = nla_get_u32((struct nlattr *) attr);
12348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		attr = RTA_NEXT(attr, attrlen);
12358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ifi->ifi_family == AF_BRIDGE && brid) {
12388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* device has been removed from bridge */
12398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		char namebuf[IFNAMSIZ];
12408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if_indextoname(brid, namebuf);
12418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Remove ifindex %u for bridge "
12428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "%s", brid, namebuf);
12438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		del_ifidx(drv, brid);
12448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
12498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    const u8 *frame, size_t len)
12508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ieee80211_mgmt *mgmt;
12528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
12538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1254d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Authenticate event");
12558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt = (const struct ieee80211_mgmt *) frame;
12568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len < 24 + sizeof(mgmt->u.auth)) {
12578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
12588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "frame");
12598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
12608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN);
12638bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
12648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
12658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
12668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
1267d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	event.auth.auth_transaction =
1268d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		le_to_host16(mgmt->u.auth.auth_transaction);
12698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.auth.status_code = le_to_host16(mgmt->u.auth.status_code);
12708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len > 24 + sizeof(mgmt->u.auth)) {
12718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.auth.ies = mgmt->u.auth.variable;
12728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth);
12738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);
12768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
127987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinenstatic unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
128087fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen{
128187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	struct nl_msg *msg;
128287fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	int ret;
128387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	struct nl80211_bss_info_arg arg;
128487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
128587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	os_memset(&arg, 0, sizeof(arg));
128687fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	msg = nlmsg_alloc();
128787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	if (!msg)
128887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		goto nla_put_failure;
128987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
12901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
129187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
129287fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
129387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	arg.drv = drv;
129487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
129587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	msg = NULL;
129687fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	if (ret == 0) {
129787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		wpa_printf(MSG_DEBUG, "nl80211: Operating frequency for the "
129887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen			   "associated BSS from scan results: %u MHz",
129987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen			   arg.assoc_freq);
1300b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		if (arg.assoc_freq)
1301b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			drv->assoc_freq = arg.assoc_freq;
1302b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return drv->assoc_freq;
130387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	}
130487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
130587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		   "(%s)", ret, strerror(-ret));
130687fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinennla_put_failure:
130787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	nlmsg_free(msg);
130887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	return drv->assoc_freq;
130987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen}
131087fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
131187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
13128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
13138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    const u8 *frame, size_t len)
13148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ieee80211_mgmt *mgmt;
13168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
13178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 status;
13188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1319d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Associate event");
13208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt = (const struct ieee80211_mgmt *) frame;
13218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
13228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
13238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "frame");
13248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
13258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	status = le_to_host16(mgmt->u.assoc_resp.status_code);
13288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (status != WLAN_STATUS_SUCCESS) {
13298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memset(&event, 0, sizeof(event));
13308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.assoc_reject.bssid = mgmt->bssid;
13318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
13328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			event.assoc_reject.resp_ies =
13338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				(u8 *) mgmt->u.assoc_resp.variable;
13348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			event.assoc_reject.resp_ies_len =
13358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				len - 24 - sizeof(mgmt->u.assoc_resp);
13368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
13378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.assoc_reject.status_code = status;
13388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
13408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
13418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->associated = 1;
13448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
13458bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	os_memcpy(drv->prev_bssid, mgmt->sa, ETH_ALEN);
13468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
13488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
13498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable;
13508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.assoc_info.resp_ies_len =
13518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			len - 24 - sizeof(mgmt->u.assoc_resp);
13528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.assoc_info.freq = drv->assoc_freq;
135504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
13568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
13578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
13618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       enum nl80211_commands cmd, struct nlattr *status,
13628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       struct nlattr *addr, struct nlattr *req_ie,
13638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       struct nlattr *resp_ie)
13648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
13668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
13688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
13698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Avoid reporting two association events that would confuse
13708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * the core code.
13718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
13728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Ignore connect event (cmd=%d) "
13738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "when using userspace SME", cmd);
13748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
13758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1377d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (cmd == NL80211_CMD_CONNECT)
1378d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Connect event");
1379d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	else if (cmd == NL80211_CMD_ROAM)
1380d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Roam event");
1381d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
13828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
13838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cmd == NL80211_CMD_CONNECT &&
13848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    nla_get_u16(status) != WLAN_STATUS_SUCCESS) {
13858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (addr)
13868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			event.assoc_reject.bssid = nla_data(addr);
13878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (resp_ie) {
13888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			event.assoc_reject.resp_ies = nla_data(resp_ie);
13898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			event.assoc_reject.resp_ies_len = nla_len(resp_ie);
13908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
13918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.assoc_reject.status_code = nla_get_u16(status);
13928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
13938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
13948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->associated = 1;
13978bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	if (addr) {
13988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
13998bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
14008bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	}
14018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (req_ie) {
14038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.assoc_info.req_ies = nla_data(req_ie);
14048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.assoc_info.req_ies_len = nla_len(req_ie);
14058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (resp_ie) {
14078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.assoc_info.resp_ies = nla_data(resp_ie);
14088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.assoc_info.resp_ies_len = nla_len(resp_ie);
14098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
141187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	event.assoc_info.freq = nl80211_get_assoc_freq(drv);
141287fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
14138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
14148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
1418c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				  struct nlattr *reason, struct nlattr *addr,
1419c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				  struct nlattr *by_ap)
14201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
14211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	union wpa_event_data data;
1422d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	unsigned int locally_generated = by_ap == NULL;
14231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
14241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
14251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		/*
14261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * Avoid reporting two disassociation events that could
14271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * confuse the core code.
14281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 */
14291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
14301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "event when using userspace SME");
14311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
14321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
14331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
1434d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (drv->ignore_next_local_disconnect) {
1435d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		drv->ignore_next_local_disconnect = 0;
1436d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		if (locally_generated) {
1437d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
1438d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt				   "event triggered during reassociation");
1439d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			return;
1440d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		}
1441d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		wpa_printf(MSG_WARNING, "nl80211: Was expecting local "
1442d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			   "disconnect but got another disconnect "
1443d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			   "event first");
1444d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	}
1445d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
1446d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Disconnect event");
14478bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	nl80211_mark_disconnected(drv);
14481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memset(&data, 0, sizeof(data));
14491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (reason)
145004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		data.deauth_info.reason_code = nla_get_u16(reason);
145104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	data.deauth_info.locally_generated = by_ap == NULL;
145204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_DEAUTH, &data);
145304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
145404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
145504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
145604949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
145704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				 struct nlattr *freq, struct nlattr *type)
145804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
145904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	union wpa_event_data data;
146004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	int ht_enabled = 1;
146104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	int chan_offset = 0;
146204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
146304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
146404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
146504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (!freq || !type)
146604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return;
146704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
146804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	switch (nla_get_u32(type)) {
146904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	case NL80211_CHAN_NO_HT:
147004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		ht_enabled = 0;
147104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		break;
147204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	case NL80211_CHAN_HT20:
147304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		break;
147404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	case NL80211_CHAN_HT40PLUS:
147504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		chan_offset = 1;
147604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		break;
147704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	case NL80211_CHAN_HT40MINUS:
147804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		chan_offset = -1;
147904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		break;
148004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
148104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
148204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	data.ch_switch.freq = nla_get_u32(freq);
148304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	data.ch_switch.ht_enabled = ht_enabled;
148404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	data.ch_switch.ch_offset = chan_offset;
148504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
148604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data);
14871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
14881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
14891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
14908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
14918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       enum nl80211_commands cmd, struct nlattr *addr)
14928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
14948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum wpa_event_type ev;
14958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nla_len(addr) != ETH_ALEN)
14978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
14988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR,
15008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   cmd, MAC2STR((u8 *) nla_data(addr)));
15018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cmd == NL80211_CMD_AUTHENTICATE)
15038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ev = EVENT_AUTH_TIMED_OUT;
15048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (cmd == NL80211_CMD_ASSOCIATE)
15058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ev = EVENT_ASSOC_TIMED_OUT;
15068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
15078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
15088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
15108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN);
15118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, ev, &event);
15128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
15138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
151604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			    struct nlattr *freq, struct nlattr *sig,
151704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			    const u8 *frame, size_t len)
15188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ieee80211_mgmt *mgmt;
15208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
15218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 fc, stype;
152204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	int ssi_signal = 0;
15238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15248da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	wpa_printf(MSG_MSGDUMP, "nl80211: Frame event");
15258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt = (const struct ieee80211_mgmt *) frame;
15268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len < 24) {
15278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Too short action frame");
15288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
15298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
15308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	fc = le_to_host16(mgmt->frame_control);
15328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	stype = WLAN_FC_GET_STYPE(fc);
15338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
153404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (sig)
153504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		ssi_signal = (s32) nla_get_u32(sig);
153604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
15378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
15388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (freq) {
15398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_action.freq = nla_get_u32(freq);
15408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->last_mgmt_freq = event.rx_action.freq;
15418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
15428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (stype == WLAN_FC_STYPE_ACTION) {
15438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_action.da = mgmt->da;
15448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_action.sa = mgmt->sa;
15458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_action.bssid = mgmt->bssid;
15468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_action.category = mgmt->u.action.category;
15478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_action.data = &mgmt->u.action.category + 1;
15488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_action.len = frame + len - event.rx_action.data;
15498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event);
15508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
15518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_mgmt.frame = frame;
15528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_mgmt.frame_len = len;
155304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		event.rx_mgmt.ssi_signal = ssi_signal;
15548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
15558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
15568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
15578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
15601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				      struct nlattr *cookie, const u8 *frame,
15611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				      size_t len, struct nlattr *ack)
15628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
15648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ieee80211_hdr *hdr;
15658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 fc;
15668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1567d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event");
15681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!is_ap_interface(drv->nlmode)) {
15691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		u64 cookie_val;
15708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (!cookie)
15721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return;
15731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
15741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		cookie_val = nla_get_u64(cookie);
15751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
15761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   " cookie=0%llx%s (ack=%d)",
15771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   (long long unsigned int) cookie_val,
15781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   cookie_val == drv->send_action_cookie ?
15791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   " (match)" : " (unknown)", ack != NULL);
15801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (cookie_val != drv->send_action_cookie)
15811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return;
15821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
15838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = (const struct ieee80211_hdr *) frame;
15858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	fc = le_to_host16(hdr->frame_control);
15868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
15888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.type = WLAN_FC_GET_TYPE(fc);
15898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
15908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.dst = hdr->addr1;
15918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.data = frame;
15928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.data_len = len;
15938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.ack = ack != NULL;
15948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
15958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
15968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
15998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       enum wpa_event_type type,
16008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       const u8 *frame, size_t len)
16018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
16028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ieee80211_mgmt *mgmt;
16038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
16048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *bssid = NULL;
16058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 reason_code = 0;
16068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1607d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (type == EVENT_DEAUTH)
1608d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Deauthenticate event");
1609d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	else
1610d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Disassociate event");
1611d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
16128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt = (const struct ieee80211_mgmt *) frame;
16138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len >= 24) {
16148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bssid = mgmt->bssid;
16158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16168bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		if ((drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
16178bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		    !drv->associated &&
16188bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		    os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0 &&
16198bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		    os_memcmp(bssid, drv->auth_attempt_bssid, ETH_ALEN) != 0 &&
16208bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		    os_memcmp(bssid, drv->prev_bssid, ETH_ALEN) == 0) {
16218bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt			/*
16228bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt			 * Avoid issues with some roaming cases where
16238bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt			 * disconnection event for the old AP may show up after
16248bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt			 * we have started connection with the new AP.
16258bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt			 */
16268bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth/disassoc event from old AP " MACSTR " when already authenticating with " MACSTR,
16278bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt				   MAC2STR(bssid),
16288bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt				   MAC2STR(drv->auth_attempt_bssid));
16298bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt			return;
16308bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		}
16318bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
16328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (drv->associated != 0 &&
16338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 &&
16348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) {
16358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/*
16368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * We have presumably received this deauth as a
16378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * response to a clear_state_mismatch() outgoing
16388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * deauth.  Don't let it take us offline!
16398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 */
16408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Deauth received "
16418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "from Unknown BSSID " MACSTR " -- ignoring",
16428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   MAC2STR(bssid));
16438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return;
16448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
16458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
16468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16478bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	nl80211_mark_disconnected(drv);
16488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
16498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Note: Same offset for Reason Code in both frame subtypes */
16518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len >= 24 + sizeof(mgmt->u.deauth))
16528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		reason_code = le_to_host16(mgmt->u.deauth.reason_code);
16538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (type == EVENT_DISASSOC) {
1655c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		event.disassoc_info.locally_generated =
1656c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			!os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
16578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.disassoc_info.addr = bssid;
16588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.disassoc_info.reason_code = reason_code;
16598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (frame + len > mgmt->u.disassoc.variable) {
16608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			event.disassoc_info.ie = mgmt->u.disassoc.variable;
16618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			event.disassoc_info.ie_len = frame + len -
16628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				mgmt->u.disassoc.variable;
16638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
16648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
1665c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		event.deauth_info.locally_generated =
1666c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			!os_memcmp(mgmt->sa, drv->first_bss.addr, ETH_ALEN);
16678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.deauth_info.addr = bssid;
16688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.deauth_info.reason_code = reason_code;
16698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (frame + len > mgmt->u.deauth.variable) {
16708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			event.deauth_info.ie = mgmt->u.deauth.variable;
16718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			event.deauth_info.ie_len = frame + len -
16728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				mgmt->u.deauth.variable;
16738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
16748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
16758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, type, &event);
16778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
16788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
16818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 enum wpa_event_type type,
16828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 const u8 *frame, size_t len)
16838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
16848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ieee80211_mgmt *mgmt;
16858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
16868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 reason_code = 0;
16878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1688d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (type == EVENT_UNPROT_DEAUTH)
1689d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Unprot Deauthenticate event");
1690d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	else
1691d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Unprot Disassociate event");
1692d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
16938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len < 24)
16948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
16958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt = (const struct ieee80211_mgmt *) frame;
16978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
16998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Note: Same offset for Reason Code in both frame subtypes */
17008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len >= 24 + sizeof(mgmt->u.deauth))
17018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		reason_code = le_to_host16(mgmt->u.deauth.reason_code);
17028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (type == EVENT_UNPROT_DISASSOC) {
17048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.unprot_disassoc.sa = mgmt->sa;
17058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.unprot_disassoc.da = mgmt->da;
17068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.unprot_disassoc.reason_code = reason_code;
17078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
17088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.unprot_deauth.sa = mgmt->sa;
17098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.unprot_deauth.da = mgmt->da;
17108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.unprot_deauth.reason_code = reason_code;
17118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, type, &event);
17148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
17158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17178da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidtstatic void mlme_event(struct i802_bss *bss,
17188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       enum nl80211_commands cmd, struct nlattr *frame,
17198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       struct nlattr *addr, struct nlattr *timed_out,
17208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       struct nlattr *freq, struct nlattr *ack,
172104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		       struct nlattr *cookie, struct nlattr *sig)
17228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
17238da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
17248da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	const u8 *data;
17258da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	size_t len;
17268da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt
17278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (timed_out && addr) {
17288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_timeout_event(drv, cmd, addr);
17298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
17308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (frame == NULL) {
173334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG,
173434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   "nl80211: MLME event %d (%s) without frame data",
173534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   cmd, nl80211_command_to_string(cmd));
17368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
17378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17398da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	data = nla_data(frame);
17408da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	len = nla_len(frame);
1741ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	if (len < 4 + 2 * ETH_ALEN) {
174234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s("
174334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   MACSTR ") - too short",
174434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   cmd, nl80211_command_to_string(cmd), bss->ifname,
174534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   MAC2STR(bss->addr));
17468da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		return;
17478da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	}
174834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR
174934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		   ") A1=" MACSTR " A2=" MACSTR, cmd,
175034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		   nl80211_command_to_string(cmd), bss->ifname,
175134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		   MAC2STR(bss->addr), MAC2STR(data + 4),
175234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		   MAC2STR(data + 4 + ETH_ALEN));
17538da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) &&
1754ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	    os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 &&
1755ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	    os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) {
17568da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event "
17578da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt			   "for foreign address", bss->ifname);
17588da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		return;
17598da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	}
17608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
17618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    nla_data(frame), nla_len(frame));
17628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (cmd) {
17648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_AUTHENTICATE:
17658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_auth(drv, nla_data(frame), nla_len(frame));
17668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
17678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_ASSOCIATE:
17688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_assoc(drv, nla_data(frame), nla_len(frame));
17698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
17708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_DEAUTHENTICATE:
17718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_deauth_disassoc(drv, EVENT_DEAUTH,
17728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   nla_data(frame), nla_len(frame));
17738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
17748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_DISASSOCIATE:
17758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_deauth_disassoc(drv, EVENT_DISASSOC,
17768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   nla_data(frame), nla_len(frame));
17778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
17788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_FRAME:
177904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		mlme_event_mgmt(drv, freq, sig, nla_data(frame),
178004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				nla_len(frame));
17818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
17828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_FRAME_TX_STATUS:
17831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
17841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					  nla_len(frame), ack);
17858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
17868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_UNPROT_DEAUTHENTICATE:
17878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH,
17888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     nla_data(frame), nla_len(frame));
17898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
17908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_UNPROT_DISASSOCIATE:
17918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC,
17928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     nla_data(frame), nla_len(frame));
17938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
17948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
17958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
17968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
17988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1800a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic void mlme_event_michael_mic_failure(struct i802_bss *bss,
18018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   struct nlattr *tb[])
18028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
18038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data data;
18048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure");
18068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
18078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_MAC]) {
18088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address",
18098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    nla_data(tb[NL80211_ATTR_MAC]),
18108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    nla_len(tb[NL80211_ATTR_MAC]));
18118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]);
18128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_KEY_SEQ]) {
18148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_DEBUG, "nl80211: TSC",
18158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    nla_data(tb[NL80211_ATTR_KEY_SEQ]),
18168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    nla_len(tb[NL80211_ATTR_KEY_SEQ]));
18178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_KEY_TYPE]) {
18198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		enum nl80211_key_type key_type =
18208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]);
18218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Key Type %d", key_type);
18228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (key_type == NL80211_KEYTYPE_PAIRWISE)
18238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			data.michael_mic_failure.unicast = 1;
18248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else
18258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data.michael_mic_failure.unicast = 1;
18268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_KEY_IDX]) {
18288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]);
18298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id);
18308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1832a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	wpa_supplicant_event(bss->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
18338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
18348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
18378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 struct nlattr *tb[])
18388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1839c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
1840c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
18418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_MAC] == NULL) {
18428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
18438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "event");
18448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
18458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
1847c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
1848c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	/* register for any AUTH message */
1849c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	nl80211_register_frame(&drv->first_bss, drv->first_bss.nl_mgmt,
1850c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			       type, NULL, 0);
1851c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
18528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->associated = 1;
18538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined",
18548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   MAC2STR(drv->bssid));
18558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
18578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
18588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv,
18618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 int cancel_event, struct nlattr *tb[])
18628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
18638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int freq, chan_type, duration;
18648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data data;
18658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u64 cookie;
18668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_WIPHY_FREQ])
18688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
18698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
18708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		freq = 0;
18718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
18738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
18748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
18758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		chan_type = 0;
18768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_DURATION])
18788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		duration = nla_get_u32(tb[NL80211_ATTR_DURATION]);
18798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
18808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		duration = 0;
18818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_COOKIE])
18838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
18848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
18858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cookie = 0;
18868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel event (cancel=%d "
18888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))",
18898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   cancel_event, freq, chan_type, duration,
18908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (long long unsigned int) cookie,
18918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   cookie == drv->remain_on_chan_cookie ? "match" : "unknown");
18928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cookie != drv->remain_on_chan_cookie)
18948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return; /* not for us */
18958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (cancel_event)
18971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		drv->pending_remain_on_chan = 0;
18988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
19008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.remain_on_channel.freq = freq;
19018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.remain_on_channel.duration = duration;
19028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, cancel_event ?
19038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     EVENT_CANCEL_REMAIN_ON_CHANNEL :
19048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     EVENT_REMAIN_ON_CHANNEL, &data);
19058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1908700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidtstatic void mlme_event_ft_event(struct wpa_driver_nl80211_data *drv,
1909700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt				struct nlattr *tb[])
1910700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt{
1911700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	union wpa_event_data data;
1912700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
1913700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
1914700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
1915700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	if (tb[NL80211_ATTR_IE]) {
1916700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt		data.ft_ies.ies = nla_data(tb[NL80211_ATTR_IE]);
1917700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt		data.ft_ies.ies_len = nla_len(tb[NL80211_ATTR_IE]);
1918700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	}
1919700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
1920700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	if (tb[NL80211_ATTR_IE_RIC]) {
1921700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt		data.ft_ies.ric_ies = nla_data(tb[NL80211_ATTR_IE_RIC]);
1922700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt		data.ft_ies.ric_ies_len = nla_len(tb[NL80211_ATTR_IE_RIC]);
1923700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	}
1924700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
1925700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	if (tb[NL80211_ATTR_MAC])
1926700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt		os_memcpy(data.ft_ies.target_ap,
1927700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt			  nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
1928700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
1929700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: FT event target_ap " MACSTR,
1930700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt		   MAC2STR(data.ft_ies.target_ap));
1931700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
1932700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_FT_RESPONSE, &data);
1933700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt}
1934700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
1935700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
19368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
19378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    struct nlattr *tb[])
19388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
19398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
19408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *nl;
19418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int rem;
19428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct scan_info *info;
19438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MAX_REPORT_FREQS 50
19448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int freqs[MAX_REPORT_FREQS];
19458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int num_freqs = 0;
19468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->scan_for_auth) {
19481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		drv->scan_for_auth = 0;
19491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing "
19501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "cfg80211 BSS entry");
19511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_driver_nl80211_authenticate_retry(drv);
19521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
19531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
19541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
19558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
19568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	info = &event.scan_info;
19578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	info->aborted = aborted;
19588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_SCAN_SSIDS]) {
19608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) {
19618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			struct wpa_driver_scan_ssid *s =
19628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				&info->ssids[info->num_ssids];
19638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			s->ssid = nla_data(nl);
19648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			s->ssid_len = nla_len(nl);
19658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			info->num_ssids++;
19668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
19678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
19688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
19698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
19718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
19728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		{
19738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			freqs[num_freqs] = nla_get_u32(nl);
19748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			num_freqs++;
19758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (num_freqs == MAX_REPORT_FREQS - 1)
19768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
19778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
19788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		info->freqs = freqs;
19798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		info->num_freqs = num_freqs;
19808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
19828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int get_link_signal(struct nl_msg *msg, void *arg)
19868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
19878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
19888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
19898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
19908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
19918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
199234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		[NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 },
19938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
19948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
19958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
19968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
19978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
19988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
19998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
20008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
20018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_signal_info *sig_change = arg;
20028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
20048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
20058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!tb[NL80211_ATTR_STA_INFO] ||
20068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
20078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     tb[NL80211_ATTR_STA_INFO], policy))
20088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
20098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!sinfo[NL80211_STA_INFO_SIGNAL])
20108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
20118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sig_change->current_signal =
20138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		(s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
20148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
201534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (sinfo[NL80211_STA_INFO_SIGNAL_AVG])
201634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		sig_change->avg_signal =
201734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			(s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL_AVG]);
201834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	else
201934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		sig_change->avg_signal = 0;
202034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
20218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
20228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
20238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     sinfo[NL80211_STA_INFO_TX_BITRATE],
20248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     rate_policy)) {
20258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			sig_change->current_txrate = 0;
20268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else {
20278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (rinfo[NL80211_RATE_INFO_BITRATE]) {
20288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				sig_change->current_txrate =
20298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					nla_get_u16(rinfo[
20308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     NL80211_RATE_INFO_BITRATE]) * 100;
20318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
20328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
20338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
20348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
20368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
20378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
20408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   struct wpa_signal_info *sig)
20418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
20428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
20438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sig->current_signal = -9999;
20458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sig->current_txrate = 0;
20468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
20488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
20498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
20508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
20528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
20548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
20558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, get_link_signal, sig);
20578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
20581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
20598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
20608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
20618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int get_link_noise(struct nl_msg *msg, void *arg)
20648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
20658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
20668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
20678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
20688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
20698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
20708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
20718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
20728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_signal_info *sig_change = arg;
20738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
20758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
20768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!tb[NL80211_ATTR_SURVEY_INFO]) {
20788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: survey data missing!");
20798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
20808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
20818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
20838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     tb[NL80211_ATTR_SURVEY_INFO],
20848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     survey_policy)) {
20858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: failed to parse nested "
20868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "attributes!");
20878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
20888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
20898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
20918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
20928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
20948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    sig_change->frequency)
20958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
20968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!sinfo[NL80211_SURVEY_INFO_NOISE])
20988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
20998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sig_change->current_noise =
21018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		(s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
21028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
21048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
21058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
21088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  struct wpa_signal_info *sig_change)
21098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
21108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
21118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sig_change->current_noise = 9999;
21138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sig_change->frequency = drv->assoc_freq;
21148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
21168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
21178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
21188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
21208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
21228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, get_link_noise, sig_change);
21248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
21251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
21261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return -ENOBUFS;
21271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
21281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
21291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
21301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
21311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
21321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
21331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
21341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
21351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
21361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		[NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
21371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		[NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
21381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	};
21391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_scan_results *scan_results = arg;
21401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_scan_res *scan_res;
21411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	size_t i;
21421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
21431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
21441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
21451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
21461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!tb[NL80211_ATTR_SURVEY_INFO]) {
21471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
21481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NL_SKIP;
21491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
21501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
21511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
21521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			     tb[NL80211_ATTR_SURVEY_INFO],
21531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			     survey_policy)) {
21541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested "
21551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "attributes");
21561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NL_SKIP;
21571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
21581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
21591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!sinfo[NL80211_SURVEY_INFO_NOISE])
21601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NL_SKIP;
21611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
21621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
21631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NL_SKIP;
21641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
21651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	for (i = 0; i < scan_results->num; ++i) {
21661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		scan_res = scan_results->res[i];
21671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (!scan_res)
21681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			continue;
21691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
21701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    scan_res->freq)
21711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			continue;
21721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
21731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			continue;
21741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		scan_res->noise = (s8)
21751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
21761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
21771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
21781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
21791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return NL_SKIP;
21801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
21811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
21821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
21831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_get_noise_for_scan_results(
21841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv,
21851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_scan_results *scan_res)
21861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
21871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_msg *msg;
21881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
21891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = nlmsg_alloc();
21901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!msg)
21911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -ENOMEM;
21921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
21931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
21941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
21951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
21961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
21971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
21981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				  scan_res);
21991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt nla_put_failure:
22001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
22018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
22028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
22038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
22068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      struct nlattr *tb[])
22078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
22088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
22098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
22108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
22118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
22128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 },
22138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
22148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
22158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum nl80211_cqm_rssi_threshold_event event;
22168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data ed;
22178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_signal_info sig;
22188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res;
22198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_CQM] == NULL ||
22218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM],
22228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     cqm_policy)) {
22238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event");
22248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
22258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
22268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&ed, 0, sizeof(ed));
22288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
22308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!tb[NL80211_ATTR_MAC])
22318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return;
22328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]),
22338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  ETH_ALEN);
22348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed);
22358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
22368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
22378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
22398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
22408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
22418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) {
22438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
22448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "event: RSSI high");
22458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ed.signal_change.above_threshold = 1;
22468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) {
22478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
22488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "event: RSSI low");
22498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ed.signal_change.above_threshold = 0;
22508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else
22518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
22528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = nl80211_get_link_signal(drv, &sig);
22548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res == 0) {
22558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ed.signal_change.current_signal = sig.current_signal;
22568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ed.signal_change.current_txrate = sig.current_txrate;
22578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm  txrate: %d",
22588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   sig.current_signal, sig.current_txrate);
22598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
22608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = nl80211_get_link_noise(drv, &sig);
22628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res == 0) {
22638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ed.signal_change.current_noise = sig.current_noise;
22648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm",
22658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   sig.current_noise);
22668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
22678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed);
22698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
22708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
22738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      struct nlattr **tb)
22748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
22758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *addr;
22768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data data;
22778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_MAC] == NULL)
22798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
22808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr = nla_data(tb[NL80211_ATTR_MAC]);
22818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr));
2282c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt
22831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
2284c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		u8 *ies = NULL;
2285c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		size_t ies_len = 0;
2286c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		if (tb[NL80211_ATTR_IE]) {
2287c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt			ies = nla_data(tb[NL80211_ATTR_IE]);
2288c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt			ies_len = nla_len(tb[NL80211_ATTR_IE]);
2289c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		}
2290c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Req IEs", ies, ies_len);
2291c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		drv_event_assoc(drv->ctx, addr, ies, ies_len, 0);
2292c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		return;
2293c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	}
2294c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt
22958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nlmode != NL80211_IFTYPE_ADHOC)
22968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
22978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
22998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN);
23008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_IBSS_RSN_START, &data);
23018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
23028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
23058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      struct nlattr **tb)
23068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
23078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *addr;
23088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data data;
23098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_MAC] == NULL)
23118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
23128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr = nla_data(tb[NL80211_ATTR_MAC]);
23138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR,
23148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   MAC2STR(addr));
2315c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt
23161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
2317c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		drv_event_disassoc(drv->ctx, addr);
2318c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		return;
2319c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	}
2320c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt
23218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nlmode != NL80211_IFTYPE_ADHOC)
23228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
23238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
23258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN);
23268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data);
23278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
23288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv,
23311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					struct nlattr **tb)
23328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
23331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA];
23341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = {
23351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		[NL80211_REKEY_DATA_KEK] = {
23361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			.minlen = NL80211_KEK_LEN,
23371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			.maxlen = NL80211_KEK_LEN,
23381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		},
23391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		[NL80211_REKEY_DATA_KCK] = {
23401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			.minlen = NL80211_KCK_LEN,
23411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			.maxlen = NL80211_KCK_LEN,
23421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		},
23431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		[NL80211_REKEY_DATA_REPLAY_CTR] = {
23441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			.minlen = NL80211_REPLAY_CTR_LEN,
23451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			.maxlen = NL80211_REPLAY_CTR_LEN,
23461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		},
23471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	};
23488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data data;
23498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!tb[NL80211_ATTR_MAC])
23511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
23521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!tb[NL80211_ATTR_REKEY_DATA])
23531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
23541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA,
23551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			     tb[NL80211_ATTR_REKEY_DATA], rekey_policy))
23561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
23571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR])
23581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
23598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memset(&data, 0, sizeof(data));
23611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]);
23621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Rekey offload event for BSSID " MACSTR,
23631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   MAC2STR(data.driver_gtk_rekey.bssid));
23641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	data.driver_gtk_rekey.replay_ctr =
23651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]);
23661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "nl80211: Rekey offload - Replay Counter",
23671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN);
23681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data);
23691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
23701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
23711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
23721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
23731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					  struct nlattr **tb)
23741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
23751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE];
23761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = {
23771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		[NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 },
23781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		[NL80211_PMKSA_CANDIDATE_BSSID] = {
23791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			.minlen = ETH_ALEN,
23801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			.maxlen = ETH_ALEN,
23811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		},
23821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		[NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG },
23831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	};
23841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	union wpa_event_data data;
23851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2386d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: PMKSA candidate event");
2387d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
23881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!tb[NL80211_ATTR_PMKSA_CANDIDATE])
23891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
23901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE,
23911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			     tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy))
23921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
23931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] ||
23941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    !cand[NL80211_PMKSA_CANDIDATE_BSSID])
23951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
23961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
23971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memset(&data, 0, sizeof(data));
23981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memcpy(data.pmkid_candidate.bssid,
23991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN);
24001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	data.pmkid_candidate.index =
24011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]);
24021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	data.pmkid_candidate.preauth =
24031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL;
24041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
24051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
24061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
24071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
24081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
24091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				       struct nlattr **tb)
24101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
24111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	union wpa_event_data data;
24121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2413d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Probe client event");
2414d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
24151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
24161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
24171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
24181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memset(&data, 0, sizeof(data));
24191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memcpy(data.client_poll.addr,
24201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
24211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
24221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
24231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
24241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
24251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2426d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtstatic void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv,
2427d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt				    struct nlattr **tb)
2428d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt{
2429d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	union wpa_event_data data;
2430d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
2431d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: TDLS operation event");
2432d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
2433d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_TDLS_OPERATION])
2434d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		return;
2435d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
2436d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	os_memset(&data, 0, sizeof(data));
2437d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	os_memcpy(data.tdls.peer, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
2438d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	switch (nla_get_u8(tb[NL80211_ATTR_TDLS_OPERATION])) {
2439d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	case NL80211_TDLS_SETUP:
2440d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: TDLS setup request for peer "
2441d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			   MACSTR, MAC2STR(data.tdls.peer));
2442d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		data.tdls.oper = TDLS_REQUEST_SETUP;
2443d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		break;
2444d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	case NL80211_TDLS_TEARDOWN:
2445d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: TDLS teardown request for peer "
2446d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			   MACSTR, MAC2STR(data.tdls.peer));
2447d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		data.tdls.oper = TDLS_REQUEST_TEARDOWN;
2448d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		break;
2449d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	default:
2450d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Unsupported TDLS operatione "
2451d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			   "event");
2452d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		return;
2453d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	}
2454d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (tb[NL80211_ATTR_REASON_CODE]) {
2455d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		data.tdls.reason_code =
2456d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			nla_get_u16(tb[NL80211_ATTR_REASON_CODE]);
2457d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	}
2458d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
2459d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_TDLS, &data);
2460d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt}
2461d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
2462d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
24635393a0f77c5281735888bd9dcf8d8abeb5961461Dmitry Shmidtstatic void nl80211_stop_ap(struct wpa_driver_nl80211_data *drv,
24645393a0f77c5281735888bd9dcf8d8abeb5961461Dmitry Shmidt			    struct nlattr **tb)
24655393a0f77c5281735888bd9dcf8d8abeb5961461Dmitry Shmidt{
24665393a0f77c5281735888bd9dcf8d8abeb5961461Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_UNAVAILABLE, NULL);
24675393a0f77c5281735888bd9dcf8d8abeb5961461Dmitry Shmidt}
24685393a0f77c5281735888bd9dcf8d8abeb5961461Dmitry Shmidt
24695393a0f77c5281735888bd9dcf8d8abeb5961461Dmitry Shmidt
2470f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtstatic void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv,
2471f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt					 struct nlattr **tb)
2472f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt{
2473f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	union wpa_event_data data;
2474f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	u32 reason;
2475f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
2476f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Connect failed event");
2477f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
2478f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_CONN_FAILED_REASON])
2479f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		return;
2480f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
2481f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
2482f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	os_memcpy(data.connect_failed_reason.addr,
2483f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		  nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
2484f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
2485f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	reason = nla_get_u32(tb[NL80211_ATTR_CONN_FAILED_REASON]);
2486f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	switch (reason) {
2487f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	case NL80211_CONN_FAIL_MAX_CLIENTS:
2488f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Max client reached");
2489f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		data.connect_failed_reason.code = MAX_CLIENT_REACHED;
2490f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		break;
2491f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	case NL80211_CONN_FAIL_BLOCKED_CLIENT:
2492f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Blocked client " MACSTR
2493f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			   " tried to connect",
2494f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			   MAC2STR(data.connect_failed_reason.addr));
2495f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		data.connect_failed_reason.code = BLOCKED_CLIENT;
2496f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		break;
2497f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	default:
2498f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl8021l: Unknown connect failed reason "
2499f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			   "%u", reason);
2500f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		return;
2501f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	}
2502f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
2503f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_CONNECT_FAILED_REASON, &data);
2504f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt}
2505f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
2506f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
2507ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidtstatic void nl80211_radar_event(struct wpa_driver_nl80211_data *drv,
2508ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt				struct nlattr **tb)
2509ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt{
2510ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	union wpa_event_data data;
2511ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	enum nl80211_radar_event event_type;
2512ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
2513ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	if (!tb[NL80211_ATTR_WIPHY_FREQ] || !tb[NL80211_ATTR_RADAR_EVENT])
2514ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		return;
2515ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
2516ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	os_memset(&data, 0, sizeof(data));
2517ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	data.dfs_event.freq = nla_get_u16(tb[NL80211_ATTR_WIPHY_FREQ]);
2518ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	event_type = nla_get_u8(tb[NL80211_ATTR_RADAR_EVENT]);
2519ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
2520ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz",
2521ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		   data.dfs_event.freq);
2522ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
2523ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	switch (event_type) {
2524ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	case NL80211_RADAR_DETECTED:
2525ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data);
2526ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		break;
2527ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	case NL80211_RADAR_CAC_FINISHED:
2528ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data);
2529ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		break;
2530ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	case NL80211_RADAR_CAC_ABORTED:
2531ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data);
2532ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		break;
2533ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	case NL80211_RADAR_NOP_FINISHED:
2534ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data);
2535ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		break;
2536ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	default:
2537ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d "
2538ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt			   "received", event_type);
2539ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		break;
2540ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	}
2541ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt}
2542ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
2543ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
25441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nl80211_spurious_frame(struct i802_bss *bss, struct nlattr **tb,
25451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   int wds)
25461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
25471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
25481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	union wpa_event_data event;
25491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!tb[NL80211_ATTR_MAC])
25511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
25521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memset(&event, 0, sizeof(event));
25541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	event.rx_from_unknown.bssid = bss->addr;
25551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]);
25561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	event.rx_from_unknown.wds = wds;
25578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
25591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
25601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
25611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2562a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtstatic void do_process_drv_event(struct i802_bss *bss, int cmd,
2563a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				 struct nlattr **tb)
25641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
2565a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
2566a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
256734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
256834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		   cmd, nl80211_command_to_string(cmd), bss->ifname);
256934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
25701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
25711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
25721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	     cmd == NL80211_CMD_SCAN_ABORTED)) {
25738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_driver_nl80211_set_mode(&drv->first_bss,
25741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					    drv->ap_scan_as_station);
25751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
25768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
25778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	switch (cmd) {
25798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_TRIGGER_SCAN:
2580700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger");
25818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
25821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_CMD_START_SCHED_SCAN:
2583700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started");
25841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
25851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_CMD_SCHED_SCAN_STOPPED:
2586700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped");
25871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
25881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
25898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_NEW_SCAN_RESULTS:
2590700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt		wpa_dbg(drv->ctx, MSG_DEBUG,
2591700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt			"nl80211: New scan results available");
25928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->scan_complete_events = 1;
25938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
25948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     drv->ctx);
25958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		send_scan_event(drv, 0, tb);
25968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
25971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_CMD_SCHED_SCAN_RESULTS:
2598700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt		wpa_dbg(drv->ctx, MSG_DEBUG,
2599700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt			"nl80211: New sched scan results available");
26001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		send_scan_event(drv, 0, tb);
26011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
26028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_SCAN_ABORTED:
2603700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
26048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
26058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Need to indicate that scan results are available in order
26068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * not to make wpa_supplicant stop its scanning.
26078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
26088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
26098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     drv->ctx);
26108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		send_scan_event(drv, 1, tb);
26118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
26128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_AUTHENTICATE:
26138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_ASSOCIATE:
26148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_DEAUTHENTICATE:
26158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_DISASSOCIATE:
26168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_FRAME_TX_STATUS:
26178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_UNPROT_DEAUTHENTICATE:
26188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_UNPROT_DISASSOCIATE:
26198da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		mlme_event(bss, cmd, tb[NL80211_ATTR_FRAME],
26208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
26218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
262204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			   tb[NL80211_ATTR_COOKIE],
262304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			   tb[NL80211_ATTR_RX_SIGNAL_DBM]);
26248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
26258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_CONNECT:
26268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_ROAM:
26271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		mlme_event_connect(drv, cmd,
26288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   tb[NL80211_ATTR_STATUS_CODE],
26298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   tb[NL80211_ATTR_MAC],
26308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   tb[NL80211_ATTR_REQ_IE],
26318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   tb[NL80211_ATTR_RESP_IE]);
26328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
263304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	case NL80211_CMD_CH_SWITCH_NOTIFY:
263404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		mlme_event_ch_switch(drv, tb[NL80211_ATTR_WIPHY_FREQ],
263504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				     tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
263604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		break;
26378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_DISCONNECT:
26381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
2639c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				      tb[NL80211_ATTR_MAC],
2640c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				      tb[NL80211_ATTR_DISCONNECTED_BY_AP]);
26418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
26428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_MICHAEL_MIC_FAILURE:
2643a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		mlme_event_michael_mic_failure(bss, tb);
26448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
26458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_JOIN_IBSS:
26468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_join_ibss(drv, tb);
26478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
26488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_REMAIN_ON_CHANNEL:
26498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_remain_on_channel(drv, 0, tb);
26508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
26518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL:
26528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_remain_on_channel(drv, 1, tb);
26538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
26548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_NOTIFY_CQM:
26558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_cqm_event(drv, tb);
26568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
26578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_REG_CHANGE:
26588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
26598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
26608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     NULL);
26618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
26628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_REG_BEACON_HINT:
26638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
26648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
26658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     NULL);
26668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
26678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_NEW_STATION:
26688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_new_station_event(drv, tb);
26698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
26708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_DEL_STATION:
26718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_del_station_event(drv, tb);
26728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
26731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_CMD_SET_REKEY_OFFLOAD:
26741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_rekey_offload_event(drv, tb);
26751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
26761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_CMD_PMKSA_CANDIDATE:
26771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_pmksa_candidate_event(drv, tb);
26781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
26791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_CMD_PROBE_CLIENT:
26801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_client_probe_event(drv, tb);
26811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
2682d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	case NL80211_CMD_TDLS_OPER:
2683d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		nl80211_tdls_oper_event(drv, tb);
2684d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		break;
2685f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	case NL80211_CMD_CONN_FAILED:
2686f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		nl80211_connect_failed_event(drv, tb);
2687f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		break;
2688700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	case NL80211_CMD_FT_EVENT:
2689700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt		mlme_event_ft_event(drv, tb);
2690700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt		break;
2691ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	case NL80211_CMD_RADAR_DETECT:
2692ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		nl80211_radar_event(drv, tb);
2693ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		break;
26945393a0f77c5281735888bd9dcf8d8abeb5961461Dmitry Shmidt	case NL80211_CMD_STOP_AP:
26955393a0f77c5281735888bd9dcf8d8abeb5961461Dmitry Shmidt		nl80211_stop_ap(drv, tb);
26965393a0f77c5281735888bd9dcf8d8abeb5961461Dmitry Shmidt		break;
26971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	default:
2698700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
2699700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt			"(cmd=%d)", cmd);
27001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
27011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
27021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
27031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
27041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
27051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int process_drv_event(struct nl_msg *msg, void *arg)
27061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
27071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = arg;
27081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
27091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
2710a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	struct i802_bss *bss;
2711a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	int ifidx = -1;
27121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
27131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
27141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
27151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
271634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (tb[NL80211_ATTR_IFINDEX]) {
2717a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
2718a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
271934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		for (bss = &drv->first_bss; bss; bss = bss->next)
272034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			if (ifidx == -1 || ifidx == bss->ifindex) {
272134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				do_process_drv_event(bss, gnlh->cmd, tb);
272234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				return NL_SKIP;
272334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			}
272434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG,
272534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   "nl80211: Ignored event (cmd=%d) for foreign interface (ifindex %d)",
272634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   gnlh->cmd, ifidx);
272734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	} else if (tb[NL80211_ATTR_WDEV]) {
272834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		u64 wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
272934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Process event on P2P device");
273034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		for (bss = &drv->first_bss; bss; bss = bss->next) {
273134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			if (bss->wdev_id_set && wdev_id == bss->wdev_id) {
273234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				do_process_drv_event(bss, gnlh->cmd, tb);
273334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				return NL_SKIP;
273434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			}
27351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
273634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG,
273734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   "nl80211: Ignored event (cmd=%d) for foreign interface (wdev 0x%llx)",
273834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   gnlh->cmd, (long long unsigned int) wdev_id);
27391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
27401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
27411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return NL_SKIP;
27421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
27431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
27441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
27451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int process_global_event(struct nl_msg *msg, void *arg)
27461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
27471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl80211_global *global = arg;
27481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
27491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
275004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpa_driver_nl80211_data *drv, *tmp;
27511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int ifidx = -1;
2752a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	struct i802_bss *bss;
275334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u64 wdev_id = 0;
275434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	int wdev_id_set = 0;
27551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
27561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
27571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
27581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
27591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (tb[NL80211_ATTR_IFINDEX])
27601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
276134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	else if (tb[NL80211_ATTR_WDEV]) {
276234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
276334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wdev_id_set = 1;
276434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
27651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
276604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	dl_list_for_each_safe(drv, tmp, &global->interfaces,
276704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			      struct wpa_driver_nl80211_data, list) {
2768a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		for (bss = &drv->first_bss; bss; bss = bss->next) {
276934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			if ((ifidx == -1 && !wdev_id_set) ||
277034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			    ifidx == bss->ifindex ||
277134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			    (wdev_id_set && bss->wdev_id_set &&
277234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			     wdev_id == bss->wdev_id)) {
2773a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				do_process_drv_event(bss, gnlh->cmd, tb);
2774a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				return NL_SKIP;
2775a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			}
2776a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		}
27771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
27781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
27791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return NL_SKIP;
27801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
27811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
27821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
27831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int process_bss_event(struct nl_msg *msg, void *arg)
27841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
27851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct i802_bss *bss = arg;
27861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
27871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
27881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
27891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
27901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
27911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
279234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: BSS Event %d (%s) received for %s",
279334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		   gnlh->cmd, nl80211_command_to_string(gnlh->cmd),
279434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		   bss->ifname);
279534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
27961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	switch (gnlh->cmd) {
27971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_CMD_FRAME:
27981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_CMD_FRAME_TX_STATUS:
27998da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		mlme_event(bss, gnlh->cmd, tb[NL80211_ATTR_FRAME],
28001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
28011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
280204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			   tb[NL80211_ATTR_COOKIE],
280304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			   tb[NL80211_ATTR_RX_SIGNAL_DBM]);
28041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
28051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_CMD_UNEXPECTED_FRAME:
28061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_spurious_frame(bss, tb, 0);
28071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
28081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_CMD_UNEXPECTED_4ADDR_FRAME:
28091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_spurious_frame(bss, tb, 1);
28101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
28118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
28128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
28138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(cmd=%d)", gnlh->cmd);
28148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
28158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
28168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
28188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
28198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
28228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     void *handle)
28238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
28241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_cb *cb = eloop_ctx;
28258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28268da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	wpa_printf(MSG_MSGDUMP, "nl80211: Event message available");
28278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_recvmsgs(handle, cb);
28298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
28308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
28338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain
28348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @priv: driver_nl80211 private data
28358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @alpha2_arg: country to which to switch to
28368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
28378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
28388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This asks nl80211 to set the regulatory domain for given
28398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * country ISO / IEC alpha2.
28408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
28418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
28428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
28438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
28448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
28458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char alpha2[3];
28468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
28478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
28498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
28508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
28518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	alpha2[0] = alpha2_arg[0];
28538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	alpha2[1] = alpha2_arg[1];
28548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	alpha2[2] = '\0';
28558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG);
28578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2);
28598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (send_and_recv_msgs(drv, msg, NULL, NULL))
28608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -EINVAL;
28618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
28628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
28631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
28648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -EINVAL;
28658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
28668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28682f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidtstatic int protocol_feature_handler(struct nl_msg *msg, void *arg)
28692f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt{
28702f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	u32 *feat = arg;
28712f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
28722f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
28732f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
28742f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
28752f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
28762f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
28772f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES])
28782f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		*feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]);
28792f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
28802f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	return NL_SKIP;
28812f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt}
28822f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
28832f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
28842f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidtstatic u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv)
28852f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt{
28862f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	u32 feat = 0;
28872f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct nl_msg *msg;
28882f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
28892f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	msg = nlmsg_alloc();
28902f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (!msg)
28912f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		goto nla_put_failure;
28922f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
28932f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_PROTOCOL_FEATURES);
28942f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat) == 0)
28952f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		return feat;
28962f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
28972f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	msg = NULL;
28982f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidtnla_put_failure:
28992f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	nlmsg_free(msg);
29002f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	return 0;
29012f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt}
29022f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
29032f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
29048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wiphy_info_data {
2905444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	struct wpa_driver_nl80211_data *drv;
29061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_capa *capa;
29071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
2908c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	unsigned int num_multichan_concurrent;
2909c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
29101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	unsigned int error:1;
29111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	unsigned int device_ap_sme:1;
29121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	unsigned int poll_command_supported:1;
29131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	unsigned int data_tx_status:1;
29141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	unsigned int monitor_supported:1;
29152f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	unsigned int auth_supported:1;
29162f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	unsigned int connect_supported:1;
29172f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	unsigned int p2p_go_supported:1;
29182f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	unsigned int p2p_client_supported:1;
29192f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	unsigned int p2p_concurrent:1;
29208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
29218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic unsigned int probe_resp_offload_support(int supp_protocols)
29241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
29251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	unsigned int prot = 0;
29261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
29271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS)
29281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS;
29291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2)
29301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2;
29311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P)
29321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P;
29331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U)
29341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING;
29351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
29361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return prot;
29371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
29381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
29391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
29402f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidtstatic void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
29412f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt					 struct nlattr *tb)
29428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
29432f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct nlattr *nl_mode;
29442f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	int i;
29452f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
29462f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (tb == NULL)
29472f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		return;
29482f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
29492f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	nla_for_each_nested(nl_mode, tb, i) {
29502f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		switch (nla_type(nl_mode)) {
29512f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		case NL80211_IFTYPE_AP:
29522f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			info->capa->flags |= WPA_DRIVER_FLAGS_AP;
29532f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			break;
2954700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt		case NL80211_IFTYPE_ADHOC:
2955700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt			info->capa->flags |= WPA_DRIVER_FLAGS_IBSS;
2956700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt			break;
295734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		case NL80211_IFTYPE_P2P_DEVICE:
295834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			info->capa->flags |=
295934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
296034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			break;
29612f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		case NL80211_IFTYPE_P2P_GO:
29622f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			info->p2p_go_supported = 1;
29632f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			break;
29642f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		case NL80211_IFTYPE_P2P_CLIENT:
29652f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			info->p2p_client_supported = 1;
29662f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			break;
29672f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		case NL80211_IFTYPE_MONITOR:
29682f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			info->monitor_supported = 1;
29692f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			break;
29702f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		}
29712f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
29722f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt}
29732f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
29742f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
29752f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidtstatic int wiphy_info_iface_comb_process(struct wiphy_info_data *info,
29762f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt					 struct nlattr *nl_combi)
29772f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt{
29782f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
29792f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
29802f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct nlattr *nl_limit, *nl_mode;
29812f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	int err, rem_limit, rem_mode;
29822f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	int combination_has_p2p = 0, combination_has_mgd = 0;
29831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	static struct nla_policy
29841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
29851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		[NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
29861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		[NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
29871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		[NL80211_IFACE_COMB_STA_AP_BI_MATCH] = { .type = NLA_FLAG },
29881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		[NL80211_IFACE_COMB_NUM_CHANNELS] = { .type = NLA_U32 },
2989ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		[NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS] = { .type = NLA_U32 },
29901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	},
29911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
29921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		[NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
29931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		[NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
29941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	};
29958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29962f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
29972f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			       nl_combi, iface_combination_policy);
29982f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
29992f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	    !tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
30002f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	    !tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS])
30012f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		return 0; /* broken combination */
30022f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
3003ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	if (tb_comb[NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS])
3004ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		info->capa->flags |= WPA_DRIVER_FLAGS_RADAR;
3005ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
30062f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	nla_for_each_nested(nl_limit, tb_comb[NL80211_IFACE_COMB_LIMITS],
30072f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			    rem_limit) {
30082f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		err = nla_parse_nested(tb_limit, MAX_NL80211_IFACE_LIMIT,
30092f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt				       nl_limit, iface_limit_policy);
30102f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		if (err || !tb_limit[NL80211_IFACE_LIMIT_TYPES])
30112f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			return 0; /* broken combination */
30122f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
30132f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		nla_for_each_nested(nl_mode,
30142f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt				    tb_limit[NL80211_IFACE_LIMIT_TYPES],
30152f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt				    rem_mode) {
30162f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			int ift = nla_type(nl_mode);
30172f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			if (ift == NL80211_IFTYPE_P2P_GO ||
30182f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			    ift == NL80211_IFTYPE_P2P_CLIENT)
30192f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt				combination_has_p2p = 1;
30202f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			if (ift == NL80211_IFTYPE_STATION)
30212f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt				combination_has_mgd = 1;
30222f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		}
30232f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		if (combination_has_p2p && combination_has_mgd)
30242f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			break;
30252f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
30262f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
30272f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (combination_has_p2p && combination_has_mgd) {
30282f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		info->p2p_concurrent = 1;
3029c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		info->num_multichan_concurrent =
3030c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]);
30312f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		return 1;
30322f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
30332f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
30342f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	return 0;
30352f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt}
30362f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
30372f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
30382f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidtstatic void wiphy_info_iface_comb(struct wiphy_info_data *info,
30392f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt				  struct nlattr *tb)
30402f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt{
30412f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct nlattr *nl_combi;
30422f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	int rem_combi;
30432f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
30442f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (tb == NULL)
30452f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		return;
30462f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
30472f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	nla_for_each_nested(nl_combi, tb, rem_combi) {
30482f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		if (wiphy_info_iface_comb_process(info, nl_combi) > 0)
30492f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			break;
30502f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
30512f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt}
30522f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
30532f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
30542f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidtstatic void wiphy_info_supp_cmds(struct wiphy_info_data *info,
30552f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt				 struct nlattr *tb)
30562f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt{
30572f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct nlattr *nl_cmd;
30582f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	int i;
30592f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
30602f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (tb == NULL)
30612f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		return;
30622f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
30632f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	nla_for_each_nested(nl_cmd, tb, i) {
30642f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		switch (nla_get_u32(nl_cmd)) {
30652f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		case NL80211_CMD_AUTHENTICATE:
30662f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			info->auth_supported = 1;
30672f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			break;
30682f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		case NL80211_CMD_CONNECT:
30692f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			info->connect_supported = 1;
30702f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			break;
30712f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		case NL80211_CMD_START_SCHED_SCAN:
30722f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			info->capa->sched_scan_supported = 1;
30732f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			break;
30742f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		case NL80211_CMD_PROBE_CLIENT:
30752f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			info->poll_command_supported = 1;
30762f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			break;
30772f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		}
30782f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
30792f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt}
30802f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
30812f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
30822f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidtstatic void wiphy_info_max_roc(struct wpa_driver_capa *capa,
30832f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			       struct nlattr *tb)
30842f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt{
30852f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (tb)
30862f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		capa->max_remain_on_chan = nla_get_u32(tb);
30872f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt}
30882f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
30892f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
30902f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidtstatic void wiphy_info_tdls(struct wpa_driver_capa *capa, struct nlattr *tdls,
30912f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			    struct nlattr *ext_setup)
30922f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt{
30932f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (tdls == NULL)
30942f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		return;
30952f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
30962f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
30972f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
30982f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
30992f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (ext_setup) {
31002f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
31012f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		capa->flags |= WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
31022f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
31032f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt}
31042f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
31052f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
31062f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidtstatic void wiphy_info_feature_flags(struct wiphy_info_data *info,
31072f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt				     struct nlattr *tb)
31082f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt{
31092f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	u32 flags;
31102f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct wpa_driver_capa *capa = info->capa;
31112f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
31122f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (tb == NULL)
31132f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		return;
31142f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
31152f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	flags = nla_get_u32(tb);
31162f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
31172f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (flags & NL80211_FEATURE_SK_TX_STATUS)
31182f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		info->data_tx_status = 1;
31192f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
31202f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
31212f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
31222f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
31232f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (flags & NL80211_FEATURE_SAE)
31242f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		capa->flags |= WPA_DRIVER_FLAGS_SAE;
31252f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
31262f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (flags & NL80211_FEATURE_NEED_OBSS_SCAN)
31272f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN;
31282f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt}
31292f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
31302f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
31312f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidtstatic void wiphy_info_probe_resp_offload(struct wpa_driver_capa *capa,
31322f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt					  struct nlattr *tb)
31332f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt{
31342f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	u32 protocols;
31352f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
31362f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (tb == NULL)
31372f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		return;
31382f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
31392f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	protocols = nla_get_u32(tb);
31402f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response offload in AP "
31412f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		   "mode");
31422f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
31432f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	capa->probe_resp_offloads = probe_resp_offload_support(protocols);
31442f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt}
31452f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
31462f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
31472f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidtstatic int wiphy_info_handler(struct nl_msg *msg, void *arg)
31482f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt{
31492f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
31502f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
31512f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct wiphy_info_data *info = arg;
31522f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct wpa_driver_capa *capa = info->capa;
3153444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = info->drv;
31542f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
31558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
31568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
31578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
315834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (tb[NL80211_ATTR_WIPHY_NAME])
315934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		os_strncpy(drv->phyname,
316034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
316134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   sizeof(drv->phyname));
31628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
31631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		capa->max_scan_ssids =
31648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
31658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
31671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		capa->max_sched_scan_ssids =
31681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
31691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
31701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (tb[NL80211_ATTR_MAX_MATCH_SETS])
31711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		capa->max_match_sets =
31721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			nla_get_u8(tb[NL80211_ATTR_MAX_MATCH_SETS]);
31731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
31748bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	if (tb[NL80211_ATTR_MAC_ACL_MAX])
31758bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		capa->max_acl_mac_addrs =
31768bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt			nla_get_u8(tb[NL80211_ATTR_MAC_ACL_MAX]);
31778bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
31782f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	wiphy_info_supported_iftypes(info, tb[NL80211_ATTR_SUPPORTED_IFTYPES]);
31792f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	wiphy_info_iface_comb(info, tb[NL80211_ATTR_INTERFACE_COMBINATIONS]);
31802f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	wiphy_info_supp_cmds(info, tb[NL80211_ATTR_SUPPORTED_COMMANDS]);
31818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
31831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
31841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "off-channel TX");
31851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
31861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
31871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
31881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (tb[NL80211_ATTR_ROAM_SUPPORT]) {
31891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Using driver-based roaming");
31901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
31911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
31921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
31932f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	wiphy_info_max_roc(capa,
31942f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			   tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
31951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
31961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
31971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
31988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31992f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	wiphy_info_tdls(capa, tb[NL80211_ATTR_TDLS_SUPPORT],
32002f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]);
3201ad266fb3da6083126e7619e525153839b918aa44Dmitry Shmidt
32021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (tb[NL80211_ATTR_DEVICE_AP_SME])
32031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		info->device_ap_sme = 1;
32041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
32052f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]);
32062f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	wiphy_info_probe_resp_offload(capa,
32072f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt				      tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
32081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
3209444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	if (tb[NL80211_ATTR_EXT_CAPA] && tb[NL80211_ATTR_EXT_CAPA_MASK] &&
3210444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	    drv->extended_capa == NULL) {
3211444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		drv->extended_capa =
3212444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt			os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
3213444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		if (drv->extended_capa) {
3214444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt			os_memcpy(drv->extended_capa,
3215444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt				  nla_data(tb[NL80211_ATTR_EXT_CAPA]),
3216444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt				  nla_len(tb[NL80211_ATTR_EXT_CAPA]));
3217444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt			drv->extended_capa_len =
3218444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt				nla_len(tb[NL80211_ATTR_EXT_CAPA]);
3219444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		}
3220444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		drv->extended_capa_mask =
3221444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt			os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
3222444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		if (drv->extended_capa_mask) {
3223444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt			os_memcpy(drv->extended_capa_mask,
3224444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt				  nla_data(tb[NL80211_ATTR_EXT_CAPA]),
3225444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt				  nla_len(tb[NL80211_ATTR_EXT_CAPA]));
3226444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		} else {
3227444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt			os_free(drv->extended_capa);
3228444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt			drv->extended_capa = NULL;
3229444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt			drv->extended_capa_len = 0;
3230444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		}
3231444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	}
3232444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt
32338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
32348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
32358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
32388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       struct wiphy_info_data *info)
32398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
32402f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	u32 feat;
32418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
32428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(info, 0, sizeof(*info));
32441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	info->capa = &drv->capa;
3245444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	info->drv = drv;
32468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
32488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
32498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
32508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32512f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	feat = get_nl80211_protocol_features(drv);
32522f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
32532f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_WIPHY);
32542f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	else
32552f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
32568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32572f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
325834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
325934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		goto nla_put_failure;
32608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32612f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
32622f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		return -1;
32632f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
32642f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (info->auth_supported)
32652f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		drv->capa.flags |= WPA_DRIVER_FLAGS_SME;
32662f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	else if (!info->connect_supported) {
32672f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		wpa_printf(MSG_INFO, "nl80211: Driver does not support "
32682f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			   "authentication/association or connect commands");
32692f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		info->error = 1;
32702f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
32712f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
32722f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (info->p2p_go_supported && info->p2p_client_supported)
32732f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
32742f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (info->p2p_concurrent) {
32752f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
32762f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			   "interface (driver advertised support)");
32772f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
32782f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
32792f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
3280c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	if (info->num_multichan_concurrent > 1) {
32812f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
32822f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			   "concurrent (driver advertised support)");
3283c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		drv->capa.num_multichan_concurrent =
3284c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			info->num_multichan_concurrent;
32852f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
328651b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt
328751b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt	/* default to 5000 since early versions of mac80211 don't set it */
328851b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt	if (!drv->capa.max_remain_on_chan)
328951b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt		drv->capa.max_remain_on_chan = 5000;
329051b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt
32912f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	return 0;
32928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
32938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
32948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
32958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
32968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
32998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
33008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wiphy_info_data info;
33018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_driver_nl80211_get_info(drv, &info))
33028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
33031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
33041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (info.error)
33051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
33061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
33078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->has_capability = 1;
33088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
33098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
33108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
33118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
33128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
33138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 |
33148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_CAPA_ENC_WEP104 |
33158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_CAPA_ENC_TKIP |
33168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_CAPA_ENC_CCMP;
33178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
33188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_AUTH_SHARED |
33198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_AUTH_LEAP;
33208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
33221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
33231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
3324ad266fb3da6083126e7619e525153839b918aa44Dmitry Shmidt
332561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (!info.device_ap_sme) {
332604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
33278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
332861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		/*
332961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		 * No AP SME is currently assumed to also indicate no AP MLME
333061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		 * in the driver/firmware.
333161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		 */
333261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		drv->capa.flags |= WPA_DRIVER_FLAGS_AP_MLME;
333361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
333461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
33351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->device_ap_sme = info.device_ap_sme;
33361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->poll_command_supported = info.poll_command_supported;
33371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->data_tx_status = info.data_tx_status;
33388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
333904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#ifdef ANDROID_P2P
334004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if(drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
334104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		/* Driver is new enough to support monitorless mode*/
334204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Driver is new "
334304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			  "enough to support monitor-less mode");
334404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		drv->use_monitor = 0;
334504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
334604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#else
33471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/*
3348aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt	 * If poll command and tx status are supported, mac80211 is new enough
3349aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt	 * to have everything we need to not need monitor interfaces.
33501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 */
3351aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt	drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
335204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#endif
33531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
33541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->device_ap_sme && drv->use_monitor) {
33551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		/*
33561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * Non-mac80211 drivers may not support monitor interface.
33571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * Make sure we do not get stuck with incorrect capability here
33581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * by explicitly testing this.
33591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 */
33601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (!info.monitor_supported) {
33611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Disable use_monitor "
33621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "with device_ap_sme since no monitor mode "
33631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "support detected");
33641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			drv->use_monitor = 0;
33651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
33668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
33678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/*
33691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * If we aren't going to use monitor interfaces, but the
33701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * driver doesn't support data TX status, we won't get TX
33711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * status for EAPOL frames.
33721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 */
33731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!drv->use_monitor && !info.data_tx_status)
33741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
33758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
33778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
33788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef ANDROID
33811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int android_genl_ctrl_resolve(struct nl_handle *handle,
33821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				     const char *name)
33838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
33841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/*
33851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * Android ICS has very minimal genl_ctrl_resolve() implementation, so
33861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * need to work around that.
33871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 */
33881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_cache *cache = NULL;
33891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct genl_family *nl80211 = NULL;
33901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int id = -1;
33918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (genl_ctrl_alloc_cache(handle, &cache) < 0) {
33931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
33941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "netlink cache");
33951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto fail;
33968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
33978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211 = genl_ctrl_search_by_name(cache, name);
33991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211 == NULL)
34001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto fail;
34018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	id = genl_family_get_id(nl80211);
34038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtfail:
34051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211)
34061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		genl_family_put(nl80211);
34071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (cache)
34081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl_cache_free(cache);
34098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return id;
34111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
34121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#define genl_ctrl_resolve android_genl_ctrl_resolve
34131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* ANDROID */
34148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
34161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
34171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
34181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int ret;
34191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
34201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
34211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (global->nl_cb == NULL) {
34221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
34231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "callbacks");
34241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
34258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
34268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	global->nl = nl_create_handle(global->nl_cb, "nl");
34281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (global->nl == NULL)
34291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto err;
34301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
34311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");
34321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (global->nl80211_id < 0) {
34338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
34348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "found");
34351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto err;
34368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
34378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	global->nl_event = nl_create_handle(global->nl_cb, "event");
34391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (global->nl_event == NULL)
34401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto err;
34411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
34421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ret = nl_get_multicast_id(global, "nl80211", "scan");
34438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret >= 0)
34441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		ret = nl_socket_add_membership(global->nl_event, ret);
34458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
34468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
34478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "membership for scan events: %d (%s)",
34488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ret, strerror(-ret));
34491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto err;
34508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
34518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ret = nl_get_multicast_id(global, "nl80211", "mlme");
34538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret >= 0)
34541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		ret = nl_socket_add_membership(global->nl_event, ret);
34558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
34568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
34578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "membership for mlme events: %d (%s)",
34588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ret, strerror(-ret));
34591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto err;
34608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
34618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ret = nl_get_multicast_id(global, "nl80211", "regulatory");
34638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret >= 0)
34641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		ret = nl_socket_add_membership(global->nl_event, ret);
34658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
34668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
34678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "membership for regulatory events: %d (%s)",
34688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ret, strerror(-ret));
34698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Continue without regulatory events */
34708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
34718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
34731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  no_seq_check, NULL);
34741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
34751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  process_global_event, global);
34761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
34771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	eloop_register_read_sock(nl_socket_get_fd(global->nl_event),
34781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				 wpa_driver_nl80211_event_receive,
34791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				 global->nl_cb, global->nl_event);
34808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
34828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidterr:
34841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_destroy_handles(&global->nl_event);
34851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_destroy_handles(&global->nl);
34861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_cb_put(global->nl_cb);
34871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	global->nl_cb = NULL;
34888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
34898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
34908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
34931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
34941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
34951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!drv->nl_cb) {
34961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to alloc cb struct");
34971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
34981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
34991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
35001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_cb_set(drv->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
35011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  no_seq_check, NULL);
35021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_cb_set(drv->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
35031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  process_drv_event, drv);
35041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
35051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
35061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
35071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
35081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
35098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_rfkill_blocked(void *ctx)
35108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
35118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
35128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
35138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * This may be for any interface; use ifdown event to disable
35148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * interface.
35158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
35168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
35178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
35208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
35218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = ctx;
35228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
3523b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (i802_set_iface_flags(&drv->first_bss, 1)) {
35248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
35258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "after rfkill unblock");
35268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
35278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
35288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* rtnetlink ifup handler will report interface as enabled */
35298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
35308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
35331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt						      void *eloop_ctx,
35341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt						      void *handle)
35351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
35361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = eloop_ctx;
35371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u8 data[2048];
35381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct msghdr msg;
35391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct iovec entry;
354004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	u8 control[512];
35411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct cmsghdr *cmsg;
35421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int res, found_ee = 0, found_wifi = 0, acked = 0;
35431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	union wpa_event_data event;
35441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
35451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	memset(&msg, 0, sizeof(msg));
35461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg.msg_iov = &entry;
35471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg.msg_iovlen = 1;
35481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	entry.iov_base = data;
35491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	entry.iov_len = sizeof(data);
35501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg.msg_control = &control;
35511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg.msg_controllen = sizeof(control);
35521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
35531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	res = recvmsg(sock, &msg, MSG_ERRQUEUE);
35541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* if error or not fitting 802.3 header, return */
35551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (res < 14)
35561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
35571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
35581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
35591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	{
35601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (cmsg->cmsg_level == SOL_SOCKET &&
35611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    cmsg->cmsg_type == SCM_WIFI_STATUS) {
35621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			int *ack;
35631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
35641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			found_wifi = 1;
35651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			ack = (void *)CMSG_DATA(cmsg);
35661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			acked = *ack;
35671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
35681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
35691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (cmsg->cmsg_level == SOL_PACKET &&
35701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    cmsg->cmsg_type == PACKET_TX_TIMESTAMP) {
35711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			struct sock_extended_err *err =
35721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				(struct sock_extended_err *)CMSG_DATA(cmsg);
35731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
35741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (err->ee_origin == SO_EE_ORIGIN_TXSTATUS)
35751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				found_ee = 1;
35761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
35771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
35781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
35791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!found_ee || !found_wifi)
35801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
35811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
35821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	memset(&event, 0, sizeof(event));
35831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	event.eapol_tx_status.dst = data;
35841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	event.eapol_tx_status.data = data + 14;
35851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	event.eapol_tx_status.data_len = res - 14;
35861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	event.eapol_tx_status.ack = acked;
35871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
35881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
35891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
35901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
35911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_init_bss(struct i802_bss *bss)
35921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
35931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
35941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!bss->nl_cb)
35951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
35961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
35971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
35981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  no_seq_check, NULL);
35991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
36001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		  process_bss_event, bss);
36011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
36021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
36031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
36041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
36051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
36061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nl80211_destroy_bss(struct i802_bss *bss)
36071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
36081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_cb_put(bss->nl_cb);
36091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	bss->nl_cb = NULL;
36101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
36111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
36121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
36138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
36148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_driver_nl80211_init - Initialize nl80211 driver interface
36158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ctx: context to be used when calling wpa_supplicant functions,
36168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * e.g., wpa_supplicant_event()
36178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ifname: interface name, e.g., wlan0
36188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @global_priv: private driver global data from global_init()
36198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Pointer to private data, %NULL on failure
36208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
36218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
36228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      void *global_priv)
36238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
36248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv;
36258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rfkill_config *rcfg;
36268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss;
36278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (global_priv == NULL)
36291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
36308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv = os_zalloc(sizeof(*drv));
36318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv == NULL)
36328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
36338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->global = global_priv;
36348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->ctx = ctx;
36358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss = &drv->first_bss;
36368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss->drv = drv;
3637a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	bss->ctx = ctx;
3638a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
36398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
36408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->monitor_ifidx = -1;
36418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->monitor_sock = -1;
36421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->eapol_tx_sock = -1;
36431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
36448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_driver_nl80211_init_nl(drv)) {
36468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(drv);
36478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
36488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
36498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211_init_bss(bss))
36518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
36528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rcfg = os_zalloc(sizeof(*rcfg));
36548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (rcfg == NULL)
36558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
36568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rcfg->ctx = drv;
36578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname));
36588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked;
36598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked;
36608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->rfkill = rfkill_init(rcfg);
36618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->rfkill == NULL) {
36628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available");
36638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(rcfg);
36648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
36658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_driver_nl80211_finish_drv_init(drv))
36678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
36688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
36701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->eapol_tx_sock < 0)
36711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto failed;
36721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
36731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->data_tx_status) {
36741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		int enabled = 1;
36751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
36761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
36771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			       &enabled, sizeof(enabled)) < 0) {
36781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG,
36791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				"nl80211: wifi status sockopt failed\n");
36801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			drv->data_tx_status = 0;
36811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (!drv->use_monitor)
36821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				drv->capa.flags &=
36831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
36841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		} else {
36851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			eloop_register_read_sock(drv->eapol_tx_sock,
36861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				wpa_driver_nl80211_handle_eapol_tx_status,
36871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				drv, NULL);
36881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
36891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
36901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
36911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->global) {
36928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dl_list_add(&drv->global->interfaces, &drv->list);
36931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		drv->in_interface_list = 1;
36941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
36958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return bss;
36978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfailed:
36991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_driver_nl80211_deinit(bss);
37008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
37018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
37028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_register_frame(struct i802_bss *bss,
37058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  struct nl_handle *nl_handle,
37068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  u16 type, const u8 *match, size_t match_len)
37078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
37081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
37098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
37108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
37118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
37138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
37148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
37158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x nl_handle=%p",
37171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   type, nl_handle);
37181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
37191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    match, match_len);
37208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
37221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
372334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (nl80211_set_iface_id(msg, bss) < 0)
372434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		goto nla_put_failure;
372534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
37268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
37278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
37288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL);
37308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
37318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
37328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
37338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "failed (type=%u): ret=%d (%s)",
37348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   type, ret, strerror(-ret));
37358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
37368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    match, match_len);
37378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
37388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
37398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = 0;
37408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
37418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
37428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
37438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
37448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
37471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
37481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
37491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
37501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (bss->nl_mgmt) {
37511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
37521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "already on! (nl_mgmt=%p)", bss->nl_mgmt);
37531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
37541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
37551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
37561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	bss->nl_mgmt = nl_create_handle(drv->nl_cb, "mgmt");
37571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (bss->nl_mgmt == NULL)
37581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
37591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
37601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	eloop_register_read_sock(nl_socket_get_fd(bss->nl_mgmt),
37611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				 wpa_driver_nl80211_event_receive, bss->nl_cb,
37621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				 bss->nl_mgmt);
37631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
37641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
37651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
37661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
37671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
37681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_register_action_frame(struct i802_bss *bss,
37698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 const u8 *match, size_t match_len)
37708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
37718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
37721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return nl80211_register_frame(bss, bss->nl_mgmt,
37738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      type, match, match_len);
37748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
37758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
37788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
37791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
37801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
37811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211_alloc_mgmt_handle(bss))
37821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
37831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
37841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   "handle %p", bss->nl_mgmt);
37851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
37861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING)
37878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* GAS Initial Request */
37881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
37898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
37908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* GAS Initial Response */
37911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0)
37928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
37938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* GAS Comeback Request */
37941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0)
37958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
37968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* GAS Comeback Response */
37971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0)
37988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
37991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* CONFIG_P2P || CONFIG_INTERWORKING */
38001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef CONFIG_P2P
38018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* P2P Public Action */
38021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211_register_action_frame(bss,
38038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  (u8 *) "\x04\x09\x50\x6f\x9a\x09",
38048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  6) < 0)
38058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
38068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* P2P Action */
38071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211_register_action_frame(bss,
38088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  (u8 *) "\x7f\x50\x6f\x9a\x09",
38098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  5) < 0)
38108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
38118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
38128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211W
38138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* SA Query Response */
38141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
38158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
38168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
38171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef CONFIG_TDLS
38181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
38191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		/* TDLS Discovery Response */
38201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) <
38211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    0)
38221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return -1;
38231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
38241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* CONFIG_TDLS */
38258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* FT Action frames */
38271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
38288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
38298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
38308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
38318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
38328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* WNM - BSS Transition Management Request */
38341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
38351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
3836a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	/* WNM-Sleep Mode Response */
3837a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
3838a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return -1;
38391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
38401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
38411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
38421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
38431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
38441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_register_spurious_class3(struct i802_bss *bss)
38451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
38461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
38471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_msg *msg;
38481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int ret = -1;
38491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
38501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = nlmsg_alloc();
38511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!msg)
38521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
38531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
38541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_UNEXPECTED_FRAME);
38551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
38561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
38571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
38581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ret = send_and_recv(drv->global, bss->nl_mgmt, msg, NULL, NULL);
38591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
38601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ret) {
38611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
38621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "failed: ret=%d (%s)",
38631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   ret, strerror(-ret));
38641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto nla_put_failure;
38651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
38661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ret = 0;
38671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtnla_put_failure:
38681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
38691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return ret;
38701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
38711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
38721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
38731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
38741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
38751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	static const int stypes[] = {
38761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		WLAN_FC_STYPE_AUTH,
38771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		WLAN_FC_STYPE_ASSOC_REQ,
38781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		WLAN_FC_STYPE_REASSOC_REQ,
38791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		WLAN_FC_STYPE_DISASSOC,
38801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		WLAN_FC_STYPE_DEAUTH,
38811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		WLAN_FC_STYPE_ACTION,
38821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		WLAN_FC_STYPE_PROBE_REQ,
38831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt/* Beacon doesn't work as mac80211 doesn't currently allow
38841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * it, but it wouldn't really be the right thing anyway as
38851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * it isn't per interface ... maybe just dump the scan
38861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * results periodically for OLBC?
38871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt */
38881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt//		WLAN_FC_STYPE_BEACON,
38891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	};
38901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	unsigned int i;
38911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
38921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211_alloc_mgmt_handle(bss))
38931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
38941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
38951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   "handle %p", bss->nl_mgmt);
38961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
38971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) {
38981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (nl80211_register_frame(bss, bss->nl_mgmt,
38991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					   (WLAN_FC_TYPE_MGMT << 2) |
39001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					   (stypes[i] << 4),
39011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					   NULL, 0) < 0) {
39021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			goto out_err;
39031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
39041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
39051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
39061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211_register_spurious_class3(bss))
39071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto out_err;
39081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
39091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211_get_wiphy_data_ap(bss) == NULL)
39101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto out_err;
39111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
39121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
39131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
39141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtout_err:
39151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
39161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_destroy_handles(&bss->nl_mgmt);
39171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return -1;
39181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
39191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
39201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
39211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
39221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
39231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211_alloc_mgmt_handle(bss))
39241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
39251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
39261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   "handle %p (device SME)", bss->nl_mgmt);
39271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
39281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211_register_frame(bss, bss->nl_mgmt,
39291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   (WLAN_FC_TYPE_MGMT << 2) |
39301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   (WLAN_FC_STYPE_ACTION << 4),
39311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   NULL, 0) < 0)
39321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto out_err;
39331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
39348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
39351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
39361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtout_err:
39371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
39381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_destroy_handles(&bss->nl_mgmt);
39391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return -1;
39401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
39411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
39421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
39431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason)
39441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
39451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (bss->nl_mgmt == NULL)
39461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
39471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
39481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   "(%s)", bss->nl_mgmt, reason);
39491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
39501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_destroy_handles(&bss->nl_mgmt);
39511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
39521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_put_wiphy_data_ap(bss);
39538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
39548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
39578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
39588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
39598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
39608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
396234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic void nl80211_del_p2pdev(struct i802_bss *bss)
396334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
396434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
396534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct nl_msg *msg;
396634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	int ret;
396734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
396834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	msg = nlmsg_alloc();
396934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (!msg)
397034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return;
397134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
397234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE);
397334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
397434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
397534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
397634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	msg = NULL;
397734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
397834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
397934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		   bss->ifname, (long long unsigned int) bss->wdev_id,
398034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		   strerror(ret));
398134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
398234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtnla_put_failure:
398334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	nlmsg_free(msg);
398434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
398534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
398634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
398734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int nl80211_set_p2pdev(struct i802_bss *bss, int start)
398834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
398934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
399034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct nl_msg *msg;
399134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	int ret = -1;
399234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
399334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	msg = nlmsg_alloc();
399434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (!msg)
399534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return -1;
399634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
399734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (start)
399834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		nl80211_cmd(drv, msg, 0, NL80211_CMD_START_P2P_DEVICE);
399934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	else
400034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_P2P_DEVICE);
400134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
400234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	NLA_PUT_U64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
400334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
400434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
400534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	msg = NULL;
400634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
400734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
400834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		   start ? "Start" : "Stop",
400934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		   bss->ifname, (long long unsigned int) bss->wdev_id,
401034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		   strerror(ret));
401134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
401234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtnla_put_failure:
401334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	nlmsg_free(msg);
401434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return ret;
401534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
401634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
401734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
401834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int i802_set_iface_flags(struct i802_bss *bss, int up)
401934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
402034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	enum nl80211_iftype nlmode;
402134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
402234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	nlmode = nl80211_get_ifmode(bss);
402334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (nlmode != NL80211_IFTYPE_P2P_DEVICE) {
402434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return linux_set_iface_flags(bss->drv->global->ioctl_sock,
402534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					     bss->ifname, up);
402634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
402734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
402834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	/* P2P Device has start/stop which is equivalent */
402934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return nl80211_set_p2pdev(bss, up);
403034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
403134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
403234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
40338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int
40348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtwpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
40358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
403634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt#ifndef HOSTAPD
403734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	enum nl80211_iftype nlmode = NL80211_IFTYPE_STATION;
403834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt#endif /* HOSTAPD */
40398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = &drv->first_bss;
40408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int send_rfkill_event = 0;
40418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->ifindex = if_nametoindex(bss->ifname);
404334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	bss->ifindex = drv->ifindex;
404434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	bss->wdev_id = drv->global->if_add_wdevid;
404534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	bss->wdev_id_set = drv->global->if_add_wdevid_set;
404634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
4047b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	bss->if_dynamic = drv->ifindex == drv->global->if_add_ifindex;
4048b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	bss->if_dynamic = bss->if_dynamic || drv->global->if_add_wdevid_set;
404934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	drv->global->if_add_wdevid_set = 0;
405034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
405134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (wpa_driver_nl80211_capa(drv))
405234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return -1;
405334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
405434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
405534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		   bss->ifname, drv->phyname);
40568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef HOSTAPD
4058b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (bss->if_dynamic)
405934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		nlmode = nl80211_get_ifmode(bss);
406034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
40611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/*
40621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * Make sure the interface starts up in station mode unless this is a
40631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * dynamically added interface (e.g., P2P) that was already configured
40641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * with proper iftype.
40651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 */
406634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (wpa_driver_nl80211_set_mode(bss, nlmode) < 0) {
406734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to use managed mode");
40681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
40698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
407034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	drv->nlmode = nlmode;
407134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
407234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
407334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		int ret = nl80211_set_p2pdev(bss, 1);
407434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (ret < 0)
407534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			wpa_printf(MSG_ERROR, "nl80211: Could not start P2P device");
407634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		nl80211_get_macaddr(bss);
407734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return ret;
407834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
40798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
40818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (rfkill_is_blocked(drv->rfkill)) {
40828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable "
40838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "interface '%s' due to rfkill",
40848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   bss->ifname);
40858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			drv->if_disabled = 1;
40868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			send_rfkill_event = 1;
40878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else {
40888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "nl80211: Could not set "
40898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "interface '%s' UP", bss->ifname);
40908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
40918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
40928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
40938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
40958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       1, IF_OPER_DORMANT);
40968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
40978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
40991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			       bss->addr))
41008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
41018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (send_rfkill_event) {
41038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
41048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       drv, drv->ctx);
41058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
41068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
41088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
41098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
41128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
41138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
41148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
41168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
41178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
41188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON);
41208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
41218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
41238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
41241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
41258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
41268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
41278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
41308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
41314b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt * @bss: Pointer to private nl80211 data from wpa_driver_nl80211_init()
41328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
41338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Shut down driver interface and processing of driver events. Free
41348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * private data buffer if one was allocated in wpa_driver_nl80211_init().
41358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
41364b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic void wpa_driver_nl80211_deinit(struct i802_bss *bss)
41378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
41388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
41398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
414004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	bss->in_deinit = 1;
41411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->data_tx_status)
41421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		eloop_unregister_read_sock(drv->eapol_tx_sock);
41431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->eapol_tx_sock >= 0)
41441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		close(drv->eapol_tx_sock);
41451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
41461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (bss->nl_preq)
41478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_driver_nl80211_probe_req_report(bss, 0);
41488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss->added_if_into_bridge) {
41491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
41501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				    bss->ifname) < 0)
41518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
41528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "interface %s from bridge %s: %s",
41538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   bss->ifname, bss->brname, strerror(errno));
41548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
41558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss->added_bridge) {
41561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
41578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
41588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "bridge %s: %s",
41598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   bss->brname, strerror(errno));
41608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
41618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl80211_remove_monitor_interface(drv);
41638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (is_ap_interface(drv->nlmode))
41658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_driver_nl80211_del_beacon(drv);
41668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
41688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->last_freq_ht) {
41698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Clear HT flags from the driver */
41708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct hostapd_freq_params freq;
41718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memset(&freq, 0, sizeof(freq));
41728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		freq.freq = drv->last_freq;
41734b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt		wpa_driver_nl80211_set_freq(bss, &freq);
41748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
41758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->eapol_sock >= 0) {
41778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_unregister_read_sock(drv->eapol_sock);
41788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		close(drv->eapol_sock);
41798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
41808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->if_indices != drv->default_if_indices)
41828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(drv->if_indices);
41838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
41848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->disabled_11b_rates)
41868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_disable_11b_rates(drv, drv->ifindex, 0);
41878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
41891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			       IF_OPER_UP);
41908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rfkill_deinit(drv->rfkill);
41918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
41938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
419434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	(void) i802_set_iface_flags(bss, 0);
419534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) {
419634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
4197b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		nl80211_mgmt_unsubscribe(bss, "deinit");
419834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	} else {
419934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		nl80211_mgmt_unsubscribe(bss, "deinit");
420034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		nl80211_del_p2pdev(bss);
420134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
42028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cb_put(drv->nl_cb);
42038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_destroy_bss(&drv->first_bss);
42051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
42068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(drv->filter_ssids);
42078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_free(drv->auth_ie);
42091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
42101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->in_interface_list)
42118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dl_list_del(&drv->list);
42128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4213444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	os_free(drv->extended_capa);
4214444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	os_free(drv->extended_capa_mask);
42158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(drv);
42168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
42178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
42208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
42218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @eloop_ctx: Driver private data
42228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
42238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
42248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function can be used as registered timeout when starting a scan to
42258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * generate a scan completed event if the driver does not report this.
42268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
42278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
42288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
42298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = eloop_ctx;
42301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
42318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_driver_nl80211_set_mode(&drv->first_bss,
42321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					    drv->ap_scan_as_station);
42331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
42348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
42358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
42368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
42378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
42388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
424061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtstatic struct nl_msg *
424161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtnl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
424234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		    struct wpa_driver_scan_params *params, u64 *wdev_id)
42438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
424461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	struct nl_msg *msg;
42458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
42468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
424861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (!msg)
424961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return NULL;
42508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
425161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	nl80211_cmd(drv, msg, 0, cmd);
42528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
425334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (!wdev_id)
425434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
425534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	else
425634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		NLA_PUT_U64(msg, NL80211_ATTR_WDEV, *wdev_id);
42578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
425861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (params->num_ssids) {
42598da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		struct nlattr *ssids;
42608da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt
42618da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		ssids = nla_nest_start(msg, NL80211_ATTR_SCAN_SSIDS);
426261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (ssids == NULL)
426361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			goto fail;
426461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		for (i = 0; i < params->num_ssids; i++) {
426561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
426661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					  params->ssids[i].ssid,
426761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					  params->ssids[i].ssid_len);
42688da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt			if (nla_put(msg, i + 1, params->ssids[i].ssid_len,
42698da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt				    params->ssids[i].ssid) < 0)
427061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				goto fail;
427161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		}
42728da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		nla_nest_end(msg, ssids);
42738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
42748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->extra_ies) {
42761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
42771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    params->extra_ies, params->extra_ies_len);
427861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
427961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			    params->extra_ies) < 0)
428061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			goto fail;
42818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
42828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->freqs) {
42848da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		struct nlattr *freqs;
42858da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
428661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (freqs == NULL)
428761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			goto fail;
42888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (i = 0; params->freqs[i]; i++) {
42898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
42908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "MHz", params->freqs[i]);
42918da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt			if (nla_put_u32(msg, i + 1, params->freqs[i]) < 0)
429261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				goto fail;
42938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
42948da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		nla_nest_end(msg, freqs);
42958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
42968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
429761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	os_free(drv->filter_ssids);
429861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	drv->filter_ssids = params->filter_ssids;
429961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	params->filter_ssids = NULL;
430061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	drv->num_filter_ssids = params->num_filter_ssids;
430161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
430261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return msg;
430361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
430461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtfail:
430534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtnla_put_failure:
430661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	nlmsg_free(msg);
430761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return NULL;
430861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
430961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
431061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
431161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt/**
431261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * wpa_driver_nl80211_scan - Request the driver to initiate scan
43134b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt * @bss: Pointer to private driver data from wpa_driver_nl80211_init()
431461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * @params: Scan parameters
431561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * Returns: 0 on success, -1 on failure
431661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt */
43174b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int wpa_driver_nl80211_scan(struct i802_bss *bss,
431861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				   struct wpa_driver_scan_params *params)
431961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
432061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
432161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	int ret = -1, timeout;
43228da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	struct nl_msg *msg = NULL;
432361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
4324700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
432561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	drv->scan_for_auth = 0;
432661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
432734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	msg = nl80211_scan_common(drv, NL80211_CMD_TRIGGER_SCAN, params,
432834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				  bss->wdev_id_set ? &bss->wdev_id : NULL);
432961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (!msg)
433061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return -1;
433161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
43321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->p2p_probe) {
43338da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		struct nlattr *rates;
43348da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt
433504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
433604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
43378da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
433861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (rates == NULL)
433961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			goto nla_put_failure;
434061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
43411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		/*
43421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
43431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * by masking out everything else apart from the OFDM rates 6,
43441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
43451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * rates are left enabled.
43461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 */
43478da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		NLA_PUT(msg, NL80211_BAND_2GHZ, 8,
43481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			"\x0c\x12\x18\x24\x30\x48\x60\x6c");
43498da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		nla_nest_end(msg, rates);
43501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
43511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
43521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
43531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
43548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
43558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
43568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
43578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
43588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", ret, strerror(-ret));
43598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
43601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (is_ap_interface(drv->nlmode)) {
43618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/*
43628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * mac80211 does not allow scan requests in AP mode, so
43638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * try to do this in station mode.
43648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 */
43651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (wpa_driver_nl80211_set_mode(
43661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				    bss, NL80211_IFTYPE_STATION))
43678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				goto nla_put_failure;
43688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43694b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt			if (wpa_driver_nl80211_scan(bss, params)) {
43701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				wpa_driver_nl80211_set_mode(bss, drv->nlmode);
43718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				goto nla_put_failure;
43728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
43738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* Restore AP mode when processing scan results */
43751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			drv->ap_scan_as_station = drv->nlmode;
43768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ret = 0;
43778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else
43788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto nla_put_failure;
43798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* HOSTAPD */
43808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
43818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
43828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
43838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Not all drivers generate "scan completed" wireless event, so try to
43858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * read results after a timeout. */
43868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	timeout = 10;
43878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->scan_complete_events) {
43888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
43898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * The driver seems to deliver events to notify when scan is
43908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * complete, so use longer timeout to avoid race conditions
43918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * with scanning and following association request.
43928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
43938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		timeout = 30;
43948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
43958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
43968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "seconds", ret, timeout);
43978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
43988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
43998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       drv, drv->ctx);
44008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
44028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
44038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
44048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
44058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt/**
44081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan
44091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
44101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @params: Scan parameters
44111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @interval: Interval between scan cycles in milliseconds
44121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * Returns: 0 on success, -1 on failure or if not supported
44131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt */
44141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int wpa_driver_nl80211_sched_scan(void *priv,
44151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					 struct wpa_driver_scan_params *params,
44161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					 u32 interval)
44178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
44181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct i802_bss *bss = priv;
44191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
442061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	int ret = -1;
442161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	struct nl_msg *msg;
44221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	size_t i;
44238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4424700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request");
4425700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
44261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef ANDROID
44271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!drv->capa.sched_scan_supported)
44281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return android_pno_start(bss, params);
44291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* ANDROID */
44301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
443134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	msg = nl80211_scan_common(drv, NL80211_CMD_START_SCHED_SCAN, params,
443234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				  bss->wdev_id_set ? &bss->wdev_id : NULL);
443361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (!msg)
443461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		goto nla_put_failure;
44351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
44361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval);
44371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
443861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if ((drv->num_filter_ssids &&
443961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	    (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
444061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	    params->filter_rssi) {
44418da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		struct nlattr *match_sets;
44428da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
444361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (match_sets == NULL)
444461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			goto nla_put_failure;
44451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
44461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		for (i = 0; i < drv->num_filter_ssids; i++) {
44478da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt			struct nlattr *match_set_ssid;
44481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_hexdump_ascii(MSG_MSGDUMP,
44491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					  "nl80211: Sched scan filter SSID",
44501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					  drv->filter_ssids[i].ssid,
44511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					  drv->filter_ssids[i].ssid_len);
44521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
44538da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt			match_set_ssid = nla_nest_start(msg, i + 1);
445461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			if (match_set_ssid == NULL)
445561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				goto nla_put_failure;
44568da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt			NLA_PUT(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
44571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				drv->filter_ssids[i].ssid_len,
44581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				drv->filter_ssids[i].ssid);
44591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
44608da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt			nla_nest_end(msg, match_set_ssid);
44611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
44621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
446361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (params->filter_rssi) {
44648da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt			struct nlattr *match_set_rssi;
44658da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt			match_set_rssi = nla_nest_start(msg, 0);
446661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			if (match_set_rssi == NULL)
446761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				goto nla_put_failure;
44688da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
446961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				    params->filter_rssi);
447061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			wpa_printf(MSG_MSGDUMP,
447161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				   "nl80211: Sched scan RSSI filter %d dBm",
447261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				   params->filter_rssi);
44738da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt			nla_nest_end(msg, match_set_rssi);
44741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
447561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
44768da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		nla_nest_end(msg, match_sets);
44771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
44781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
44791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
44801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
44811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* TODO: if we get an error here, we should fall back to normal scan */
44821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
44831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
44841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ret) {
44851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: "
44861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "ret=%d (%s)", ret, strerror(-ret));
44871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto nla_put_failure;
44881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
44891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
44901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
44911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   "scan interval %d msec", ret, interval);
44921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
44931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtnla_put_failure:
44941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
44951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return ret;
44961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
44971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
44981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
44991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt/**
45001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan
45011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
45021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt * Returns: 0 on success, -1 on failure or if not supported
45031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt */
45041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int wpa_driver_nl80211_stop_sched_scan(void *priv)
45051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
45061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct i802_bss *bss = priv;
45071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
45081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int ret = 0;
45091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_msg *msg;
45101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
45111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef ANDROID
45121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!drv->capa.sched_scan_supported)
45131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return android_pno_stop(bss);
45141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* ANDROID */
45151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
45161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = nlmsg_alloc();
45171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!msg)
45181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
45191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
45201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_SCHED_SCAN);
45211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
45221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
45231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
45241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
45251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
45261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ret) {
45271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop failed: "
45281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "ret=%d (%s)", ret, strerror(-ret));
45291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto nla_put_failure;
45301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
45311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
45321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop sent (ret=%d)", ret);
45331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
45341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtnla_put_failure:
45351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
45361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return ret;
45371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
45381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
45391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
45401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
45411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
45421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const u8 *end, *pos;
45431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
45441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ies == NULL)
45451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return NULL;
45461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
45471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	pos = ies;
45481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	end = ies + ies_len;
45498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pos + 1 < end) {
45518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos + 2 + pos[1] > end)
45528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
45538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos[0] == ie)
45548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return pos;
45558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2 + pos[1];
45568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
45578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
45598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
45608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
45638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 const u8 *ie, size_t ie_len)
45648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
45658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *ssid;
45668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
45678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->filter_ssids == NULL)
45698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
45708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID);
45728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ssid == NULL)
45738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 1;
45748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < drv->num_filter_ssids; i++) {
45768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ssid[1] == drv->filter_ssids[i].ssid_len &&
45778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) ==
45788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0)
45798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 0;
45808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
45818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 1;
45838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
45848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int bss_info_handler(struct nl_msg *msg, void *arg)
45878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
45888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
45898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
45908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *bss[NL80211_BSS_MAX + 1];
45918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
45928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
45938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
45948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_TSF] = { .type = NLA_U64 },
45958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
45968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
45978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
45988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
45998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
46008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_STATUS] = { .type = NLA_U32 },
46018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
46028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
46038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
46048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl80211_bss_info_arg *_arg = arg;
46058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_results *res = _arg->res;
46068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_res **tmp;
46078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_res *r;
46088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *ie, *beacon_ie;
46098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t ie_len, beacon_ie_len;
46108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *pos;
461187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	size_t i;
46128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
46138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
46148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
46158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!tb[NL80211_ATTR_BSS])
46168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
46178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
46188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     bss_policy))
46198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
462087fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	if (bss[NL80211_BSS_STATUS]) {
462187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		enum nl80211_bss_status status;
462287fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		status = nla_get_u32(bss[NL80211_BSS_STATUS]);
462387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		if (status == NL80211_BSS_STATUS_ASSOCIATED &&
462487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		    bss[NL80211_BSS_FREQUENCY]) {
462587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen			_arg->assoc_freq =
462687fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen				nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
462787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen			wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
462887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen				   _arg->assoc_freq);
462987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		}
46301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (status == NL80211_BSS_STATUS_ASSOCIATED &&
46311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    bss[NL80211_BSS_BSSID]) {
46321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			os_memcpy(_arg->assoc_bssid,
46331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				  nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
46341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Associated with "
46351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   MACSTR, MAC2STR(_arg->assoc_bssid));
46361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
463787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	}
463887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	if (!res)
463987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		return NL_SKIP;
46408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
46418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
46428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
46438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
46448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ie = NULL;
46458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ie_len = 0;
46468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
46478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss[NL80211_BSS_BEACON_IES]) {
46488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]);
46498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]);
46508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
46518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		beacon_ie = NULL;
46528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		beacon_ie_len = 0;
46538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
46548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
46558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
46568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  ie ? ie_len : beacon_ie_len))
46578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
46588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
46598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
46608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (r == NULL)
46618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
46628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss[NL80211_BSS_BSSID])
46638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
46648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  ETH_ALEN);
46658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss[NL80211_BSS_FREQUENCY])
46668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
46678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss[NL80211_BSS_BEACON_INTERVAL])
46688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
46698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss[NL80211_BSS_CAPABILITY])
46708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
46718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	r->flags |= WPA_SCAN_NOISE_INVALID;
46728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss[NL80211_BSS_SIGNAL_MBM]) {
46738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
46748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->level /= 100; /* mBm to dBm */
46758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
46768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
46778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
46781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		r->flags |= WPA_SCAN_QUAL_INVALID;
46798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else
46808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
46818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss[NL80211_BSS_TSF])
46828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
46838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss[NL80211_BSS_SEEN_MS_AGO])
46848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
46858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	r->ie_len = ie_len;
46868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = (u8 *) (r + 1);
46878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ie) {
46888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(pos, ie, ie_len);
46898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += ie_len;
46908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
46918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	r->beacon_ie_len = beacon_ie_len;
46928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (beacon_ie)
46938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(pos, beacon_ie, beacon_ie_len);
46948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
46958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss[NL80211_BSS_STATUS]) {
46968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		enum nl80211_bss_status status;
46978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		status = nla_get_u32(bss[NL80211_BSS_STATUS]);
46988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (status) {
46998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case NL80211_BSS_STATUS_AUTHENTICATED:
47008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			r->flags |= WPA_SCAN_AUTHENTICATED;
47018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
47028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case NL80211_BSS_STATUS_ASSOCIATED:
47038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			r->flags |= WPA_SCAN_ASSOCIATED;
47048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
47058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
47068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
47078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
47088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
47098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
471087fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	/*
471187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	 * cfg80211 maintains separate BSS table entries for APs if the same
471287fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	 * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
471387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	 * not use frequency as a separate key in the BSS table, so filter out
471487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	 * duplicated entries. Prefer associated BSS entry in such a case in
471587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	 * order to get the correct frequency into the BSS table.
471687fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	 */
471787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	for (i = 0; i < res->num; i++) {
471887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		const u8 *s1, *s2;
471987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0)
472087fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen			continue;
472187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
472287fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		s1 = nl80211_get_ie((u8 *) (res->res[i] + 1),
472387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen				    res->res[i]->ie_len, WLAN_EID_SSID);
472487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		s2 = nl80211_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
472587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
472687fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		    os_memcmp(s1, s2, 2 + s1[1]) != 0)
472787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen			continue;
472887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
472987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		/* Same BSSID,SSID was already included in scan results */
473087fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
473187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen			   "for " MACSTR, MAC2STR(r->bssid));
473287fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
473387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		if ((r->flags & WPA_SCAN_ASSOCIATED) &&
473487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		    !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) {
473587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen			os_free(res->res[i]);
473687fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen			res->res[i] = r;
473787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		} else
473887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen			os_free(r);
473987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		return NL_SKIP;
474087fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	}
474187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
474261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	tmp = os_realloc_array(res->res, res->num + 1,
474361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			       sizeof(struct wpa_scan_res *));
47448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tmp == NULL) {
47458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(r);
47468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
47478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
47488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tmp[res->num++] = r;
47498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res->res = tmp;
47508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
47528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
47538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void clear_state_mismatch(struct wpa_driver_nl80211_data *drv,
47568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 const u8 *addr)
47578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
47588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
47598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Clear possible state "
47608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "mismatch (" MACSTR ")", MAC2STR(addr));
47618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_driver_nl80211_mlme(drv, addr,
47628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					NL80211_CMD_DEAUTHENTICATE,
47638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					WLAN_REASON_PREV_AUTH_NOT_VALID, 1);
47648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
47658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
47668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_check_bss_status(
47698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res)
47708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
47718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
47728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < res->num; i++) {
47748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wpa_scan_res *r = res->res[i];
47758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (r->flags & WPA_SCAN_AUTHENTICATED) {
47768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Scan results "
47778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "indicates BSS status with " MACSTR
47788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   " as authenticated",
47798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   MAC2STR(r->bssid));
47801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (is_sta_interface(drv->nlmode) &&
47818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 &&
47828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) !=
47838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    0) {
47848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "nl80211: Unknown BSSID"
47858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   " in local state (auth=" MACSTR
47868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   " assoc=" MACSTR ")",
47878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   MAC2STR(drv->auth_bssid),
47888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   MAC2STR(drv->bssid));
47898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				clear_state_mismatch(drv, r->bssid);
47908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
47918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
47928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (r->flags & WPA_SCAN_ASSOCIATED) {
47948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Scan results "
47958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "indicate BSS status with " MACSTR
47968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   " as associated",
47978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   MAC2STR(r->bssid));
47981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (is_sta_interface(drv->nlmode) &&
47998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    !drv->associated) {
48008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "nl80211: Local state "
48018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "(not associated) does not match "
48028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "with BSS state");
48038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				clear_state_mismatch(drv, r->bssid);
48041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			} else if (is_sta_interface(drv->nlmode) &&
48058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
48068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   0) {
48078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "nl80211: Local state "
48088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "(associated with " MACSTR ") does "
48098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "not match with BSS state",
48108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   MAC2STR(drv->bssid));
48118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				clear_state_mismatch(drv, r->bssid);
48128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				clear_state_mismatch(drv, drv->bssid);
48138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
48148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
48158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
48168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
48178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpa_scan_results *
48208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
48218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
48228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
48238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_results *res;
48248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
48258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl80211_bss_info_arg arg;
48268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = os_zalloc(sizeof(*res));
48288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res == NULL)
48298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
48308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
48318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
48328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
48338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
483534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
483634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		goto nla_put_failure;
48378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	arg.drv = drv;
48398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	arg.res = res;
48408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
48418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
48428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == 0) {
48431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
48441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "BSSes)", (unsigned long) res->num);
48451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_get_noise_for_scan_results(drv, res);
48468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return res;
48478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
48488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
48498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "(%s)", ret, strerror(-ret));
48508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
48518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
48528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_scan_results_free(res);
48538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
48548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
48558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
48588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
48598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
48608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Scan results on success, -1 on failure
48618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
48628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpa_scan_results *
48638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtwpa_driver_nl80211_get_scan_results(void *priv)
48648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
48658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
48668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
48678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_results *res;
48688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = nl80211_get_scan_results(drv);
48708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res)
48718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_driver_nl80211_check_bss_status(drv, res);
48728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return res;
48738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
48748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
48778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
48788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_results *res;
48798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
48808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = nl80211_get_scan_results(drv);
48828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res == NULL) {
48838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
48848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
48858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
48868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
48888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < res->num; i++) {
48898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wpa_scan_res *r = res->res[i];
48908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s%s",
48918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (int) i, (int) res->num, MAC2STR(r->bssid),
48928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   r->flags & WPA_SCAN_AUTHENTICATED ? " [auth]" : "",
48938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
48948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
48958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_scan_results_free(res);
48978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
48988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49004b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
49018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      enum wpa_alg alg, const u8 *addr,
49028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      int key_idx, int set_tx,
49038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      const u8 *seq, size_t seq_len,
49048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      const u8 *key, size_t key_len)
49058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
49068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
490734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	int ifindex;
49088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
49098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
4910d5c075b0c218277d0f926daf1f9eff974b9656dcDmitry Shmidt	int tdls = 0;
49118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
491234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	/* Ignore for P2P Device */
491334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
491434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return 0;
491534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
491634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ifindex = if_nametoindex(ifname);
491734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s: ifindex=%d (%s) alg=%d addr=%p key_idx=%d "
49188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "set_tx=%d seq_len=%lu key_len=%lu",
491934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		   __func__, ifindex, ifname, alg, addr, key_idx, set_tx,
49208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (unsigned long) seq_len, (unsigned long) key_len);
49211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef CONFIG_TDLS
4922d5c075b0c218277d0f926daf1f9eff974b9656dcDmitry Shmidt	if (key_idx == -1) {
49231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		key_idx = 0;
4924d5c075b0c218277d0f926daf1f9eff974b9656dcDmitry Shmidt		tdls = 1;
4925d5c075b0c218277d0f926daf1f9eff974b9656dcDmitry Shmidt	}
49261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* CONFIG_TDLS */
49278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
49298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
49308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
49318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (alg == WPA_ALG_NONE) {
49331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_KEY);
49348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
49351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY);
49368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
49378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (alg) {
49388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case WPA_ALG_WEP:
49398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (key_len == 5)
49408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
49418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    WLAN_CIPHER_SUITE_WEP40);
49428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else
49438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
49448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    WLAN_CIPHER_SUITE_WEP104);
49458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
49468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case WPA_ALG_TKIP:
49478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
49488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    WLAN_CIPHER_SUITE_TKIP);
49498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
49508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case WPA_ALG_CCMP:
49518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
49528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    WLAN_CIPHER_SUITE_CCMP);
49538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
495461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		case WPA_ALG_GCMP:
495561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
495661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				    WLAN_CIPHER_SUITE_GCMP);
495761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			break;
49588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case WPA_ALG_IGTK:
49598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
49608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    WLAN_CIPHER_SUITE_AES_CMAC);
49618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
4962d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		case WPA_ALG_SMS4:
4963d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4964d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt				    WLAN_CIPHER_SUITE_SMS4);
4965d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			break;
4966d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		case WPA_ALG_KRK:
4967d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
4968d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt				    WLAN_CIPHER_SUITE_KRK);
4969d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			break;
49708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
49718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
49728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "algorithm %d", __func__, alg);
49738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nlmsg_free(msg);
49748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
49758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
49768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
49778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (seq && seq_len)
49798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq);
49808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (addr && !is_broadcast_ether_addr(addr)) {
49828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "   addr=" MACSTR, MAC2STR(addr));
49838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
49848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (alg != WPA_ALG_WEP && key_idx && !set_tx) {
49868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "   RSN IBSS RX GTK");
49878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE,
49888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    NL80211_KEYTYPE_GROUP);
49898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
49908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (addr && is_broadcast_ether_addr(addr)) {
49918da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		struct nlattr *types;
49928da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt
49938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "   broadcast key");
49948da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt
49958da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
49968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!types)
49978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto nla_put_failure;
49988da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
49998da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		nla_nest_end(msg, types);
50008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
50018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
50028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
50038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
50058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
50068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = 0;
50078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret)
50088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s)",
50098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ret, strerror(-ret));
50108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
50128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * If we failed or don't need to set the default TX key (below),
50138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * we're done here.
50148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
5015d5c075b0c218277d0f926daf1f9eff974b9656dcDmitry Shmidt	if (ret || !set_tx || alg == WPA_ALG_NONE || tdls)
50168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ret;
50171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (is_ap_interface(drv->nlmode) && addr &&
50188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    !is_broadcast_ether_addr(addr))
50198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ret;
50208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
50228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
50238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
50248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_KEY);
50268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
50278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
50288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (alg == WPA_ALG_IGTK)
50298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT);
50308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
50318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
50328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (addr && is_broadcast_ether_addr(addr)) {
50338da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		struct nlattr *types;
50348da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt
50358da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
50368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!types)
50378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto nla_put_failure;
50388da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
50398da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		nla_nest_end(msg, types);
50408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (addr) {
50418da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		struct nlattr *types;
50428da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt
50438da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
50448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!types)
50458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto nla_put_failure;
50468da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST);
50478da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		nla_nest_end(msg, types);
50488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
50498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
50518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == -ENOENT)
50528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = 0;
50538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret)
50548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: set_key default failed; "
50558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "err=%d %s)", ret, strerror(-ret));
50568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
50578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
50591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
50608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
50618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
50628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
50658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      int key_idx, int defkey,
50668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      const u8 *seq, size_t seq_len,
50678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      const u8 *key, size_t key_len)
50688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
50698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY);
50708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!key_attr)
50718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
50728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (defkey && alg == WPA_ALG_IGTK)
50748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_MGMT);
50758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (defkey)
50768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
50778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx);
50798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (alg) {
50818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_ALG_WEP:
50828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (key_len == 5)
50838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
50848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    WLAN_CIPHER_SUITE_WEP40);
50858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else
50868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
50878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    WLAN_CIPHER_SUITE_WEP104);
50888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
50898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_ALG_TKIP:
50908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_TKIP);
50918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
50928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_ALG_CCMP:
50938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP);
50948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
509561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	case WPA_ALG_GCMP:
509661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_GCMP);
509761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		break;
50988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_ALG_IGTK:
50998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
51008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    WLAN_CIPHER_SUITE_AES_CMAC);
51018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
51028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
51038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
51048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "algorithm %d", __func__, alg);
51058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
51068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
51078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (seq && seq_len)
51098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_KEY_SEQ, seq_len, seq);
51108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_KEY_DATA, key_len, key);
51128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_nest_end(msg, key_attr);
51148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
51168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
51178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
51188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
51198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_set_conn_keys(struct wpa_driver_associate_params *params,
51228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 struct nl_msg *msg)
51238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
51248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i, privacy = 0;
51258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *nl_keys, *nl_key;
51268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < 4; i++) {
51288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!params->wep_key[i])
51298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
51308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		privacy = 1;
51318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
51328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
51338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->wps == WPS_MODE_PRIVACY)
51348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		privacy = 1;
51358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->pairwise_suite &&
51368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    params->pairwise_suite != WPA_CIPHER_NONE)
51378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		privacy = 1;
51388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!privacy)
51408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
51418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
51438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
51458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!nl_keys)
51468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
51478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < 4; i++) {
51498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!params->wep_key[i])
51508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
51518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl_key = nla_nest_start(msg, i);
51538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!nl_key)
51548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto nla_put_failure;
51558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_KEY_DATA, params->wep_key_len[i],
51578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->wep_key[i]);
51588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->wep_key_len[i] == 5)
51598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
51608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    WLAN_CIPHER_SUITE_WEP40);
51618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else
51628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
51638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    WLAN_CIPHER_SUITE_WEP104);
51648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U8(msg, NL80211_KEY_IDX, i);
51668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (i == params->wep_tx_keyidx)
51688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
51698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_nest_end(msg, nl_key);
51718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
51728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_nest_end(msg, nl_keys);
51738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
51758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
51778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
51788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
51798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
51828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   const u8 *addr, int cmd, u16 reason_code,
51838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   int local_state_change)
51848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
51858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
51868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
51878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
51898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
51908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
51918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, cmd);
51938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
51958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code);
5196d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (addr)
5197d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
51988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (local_state_change)
51998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
52008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
52028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
52038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
52041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_dbg(drv->ctx, MSG_DEBUG,
52051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			"nl80211: MLME command failed: reason=%u ret=%d (%s)",
52061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			reason_code, ret, strerror(-ret));
52078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
52088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
52098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = 0;
52108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
52128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
52138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
52148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
52158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
5218d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt					 int reason_code)
52198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5220c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	int ret;
5221c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
5222d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	wpa_printf(MSG_DEBUG, "%s(reason_code=%d)", __func__, reason_code);
52238bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	nl80211_mark_disconnected(drv);
5224d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	/* Disconnect command doesn't need BSSID - it uses cached value */
5225c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	ret = wpa_driver_nl80211_mlme(drv, NULL, NL80211_CMD_DISCONNECT,
5226c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt				      reason_code, 0);
5227c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	/*
5228c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	 * For locally generated disconnect, supplicant already generates a
5229c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	 * DEAUTH event, so ignore the event from NL80211.
5230c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	 */
5231c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	drv->ignore_next_local_disconnect = ret == 0;
5232c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
5233c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	return ret;
52348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
52358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52374b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int wpa_driver_nl80211_deauthenticate(struct i802_bss *bss,
52384b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					     const u8 *addr, int reason_code)
52398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
52408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
52418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
5242d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		return wpa_driver_nl80211_disconnect(drv, reason_code);
52438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
52448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   __func__, MAC2STR(addr), reason_code);
52458bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	nl80211_mark_disconnected(drv);
52468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nlmode == NL80211_IFTYPE_ADHOC)
52478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return nl80211_leave_ibss(drv);
52488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
52498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       reason_code, 0);
52508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
52518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
52541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				     struct wpa_driver_auth_params *params)
52551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
52561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int i;
52571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
52581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->auth_freq = params->freq;
52591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->auth_alg = params->auth_alg;
52601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->auth_wep_tx_keyidx = params->wep_tx_keyidx;
52611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->auth_local_state_change = params->local_state_change;
52621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->auth_p2p = params->p2p;
52631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
52641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->bssid)
52651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		os_memcpy(drv->auth_bssid_, params->bssid, ETH_ALEN);
52661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	else
52671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		os_memset(drv->auth_bssid_, 0, ETH_ALEN);
52681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
52691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->ssid) {
52701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		os_memcpy(drv->auth_ssid, params->ssid, params->ssid_len);
52711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		drv->auth_ssid_len = params->ssid_len;
52721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else
52731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		drv->auth_ssid_len = 0;
52741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
52751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
52761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_free(drv->auth_ie);
52771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->auth_ie = NULL;
52781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->auth_ie_len = 0;
52791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->ie) {
52801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		drv->auth_ie = os_malloc(params->ie_len);
52811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (drv->auth_ie) {
52821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			os_memcpy(drv->auth_ie, params->ie, params->ie_len);
52831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			drv->auth_ie_len = params->ie_len;
52841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
52851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
52861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
52871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	for (i = 0; i < 4; i++) {
52881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (params->wep_key[i] && params->wep_key_len[i] &&
52891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    params->wep_key_len[i] <= 16) {
52901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			os_memcpy(drv->auth_wep_key[i], params->wep_key[i],
52911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				  params->wep_key_len[i]);
52921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			drv->auth_wep_key_len[i] = params->wep_key_len[i];
52931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		} else
52941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			drv->auth_wep_key_len[i] = 0;
52951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
52961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
52971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
52981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
52998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_authenticate(
53004b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct i802_bss *bss, struct wpa_driver_auth_params *params)
53018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
53028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
53038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1, i;
53048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
53058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum nl80211_auth_type type;
53061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	enum nl80211_iftype nlmode;
53078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int count = 0;
53081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int is_retry;
53091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
53101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	is_retry = drv->retry_auth;
53111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->retry_auth = 0;
53128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53138bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	nl80211_mark_disconnected(drv);
53148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(drv->auth_bssid, 0, ETH_ALEN);
53158bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	if (params->bssid)
53168bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		os_memcpy(drv->auth_attempt_bssid, params->bssid, ETH_ALEN);
53178bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	else
53188bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		os_memset(drv->auth_attempt_bssid, 0, ETH_ALEN);
53198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* FIX: IBSS mode */
53201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmode = params->p2p ?
53211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
53221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->nlmode != nlmode &&
53234b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	    wpa_driver_nl80211_set_mode(bss, nlmode) < 0)
53248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
53258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtretry:
53278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
53288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
53298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
53308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
53328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   drv->ifindex);
53338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_AUTHENTICATE);
53358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < 4; i++) {
53378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!params->wep_key[i])
53388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
53394b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt		wpa_driver_nl80211_set_key(bss->ifname, bss, WPA_ALG_WEP,
53408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   NULL, i,
53418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   i == params->wep_tx_keyidx, NULL, 0,
53428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   params->wep_key[i],
53438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   params->wep_key_len[i]);
53448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->wep_tx_keyidx != i)
53458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
53468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
53478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       params->wep_key[i], params->wep_key_len[i])) {
53488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nlmsg_free(msg);
53498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
53508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
53518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
53528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
53548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->bssid) {
53558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * bssid=" MACSTR,
53568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(params->bssid));
53578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
53588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
53598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->freq) {
53608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
53618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
53628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
53638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->ssid) {
53648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
53658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  params->ssid, params->ssid_len);
53668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
53678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->ssid);
53688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
53698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "  * IEs", params->ie, params->ie_len);
53708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->ie)
53718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_IE, params->ie_len, params->ie);
5372d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (params->sae_data) {
5373d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "  * SAE data", params->sae_data,
5374d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			    params->sae_data_len);
5375d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_SAE_DATA, params->sae_data_len,
5376d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			params->sae_data);
5377d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	}
53788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->auth_alg & WPA_AUTH_ALG_OPEN)
53798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		type = NL80211_AUTHTYPE_OPEN_SYSTEM;
53808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
53818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		type = NL80211_AUTHTYPE_SHARED_KEY;
53828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
53838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		type = NL80211_AUTHTYPE_NETWORK_EAP;
53848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (params->auth_alg & WPA_AUTH_ALG_FT)
53858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		type = NL80211_AUTHTYPE_FT;
5386d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	else if (params->auth_alg & WPA_AUTH_ALG_SAE)
5387d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		type = NL80211_AUTHTYPE_SAE;
53888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
53898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
53908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "  * Auth Type %d", type);
53918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
53928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->local_state_change) {
53938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * Local state change only");
53948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
53958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
53968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
53988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
53998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
54001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_dbg(drv->ctx, MSG_DEBUG,
54011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			"nl80211: MLME command failed (auth): ret=%d (%s)",
54021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			ret, strerror(-ret));
54038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		count++;
54048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret == -EALREADY && count == 1 && params->bssid &&
54058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    !params->local_state_change) {
54068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/*
54078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * mac80211 does not currently accept new
54088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * authentication if we are already authenticated. As a
54098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * workaround, force deauthentication and try again.
54108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 */
54118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Retry authentication "
54128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "after forced deauthentication");
54138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_driver_nl80211_deauthenticate(
54148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				bss, params->bssid,
54158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				WLAN_REASON_PREV_AUTH_NOT_VALID);
54168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nlmsg_free(msg);
54178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto retry;
54188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
54191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
54201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (ret == -ENOENT && params->freq && !is_retry) {
54211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			/*
54221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 * cfg80211 has likely expired the BSS entry even
54231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 * though it was previously available in our internal
54241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 * BSS table. To recover quickly, start a single
54251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 * channel scan on the specified channel.
54261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 */
54271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			struct wpa_driver_scan_params scan;
54281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			int freqs[2];
54291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
54301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			os_memset(&scan, 0, sizeof(scan));
54311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			scan.num_ssids = 1;
54321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (params->ssid) {
54331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				scan.ssids[0].ssid = params->ssid;
54341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				scan.ssids[0].ssid_len = params->ssid_len;
54351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			}
54361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			freqs[0] = params->freq;
54371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			freqs[1] = 0;
54381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			scan.freqs = freqs;
54391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Trigger single "
54401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "channel scan to refresh cfg80211 BSS "
54411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "entry");
54421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			ret = wpa_driver_nl80211_scan(bss, &scan);
54431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (ret == 0) {
54441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				nl80211_copy_auth_params(drv, params);
54451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				drv->scan_for_auth = 1;
54461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			}
54471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		} else if (is_retry) {
54481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			/*
54491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 * Need to indicate this with an event since the return
54501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 * value from the retry is not delivered to core code.
54511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 */
54521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			union wpa_event_data event;
54531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Authentication retry "
54541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "failed");
54551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			os_memset(&event, 0, sizeof(event));
54561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			os_memcpy(event.timeout_event.addr, drv->auth_bssid_,
54571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				  ETH_ALEN);
54581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT,
54591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					     &event);
54601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
54611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
54628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
54638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
54648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = 0;
54658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Authentication request send "
54668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "successfully");
54678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
54698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
54708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
54718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
54728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int wpa_driver_nl80211_authenticate_retry(
54751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv)
54761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
54771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_auth_params params;
54781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct i802_bss *bss = &drv->first_bss;
54791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int i;
54801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
54811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
54821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
54831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memset(&params, 0, sizeof(params));
54841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	params.freq = drv->auth_freq;
54851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	params.auth_alg = drv->auth_alg;
54861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	params.wep_tx_keyidx = drv->auth_wep_tx_keyidx;
54871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	params.local_state_change = drv->auth_local_state_change;
54881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	params.p2p = drv->auth_p2p;
54891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
54901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!is_zero_ether_addr(drv->auth_bssid_))
54911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		params.bssid = drv->auth_bssid_;
54921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
54931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->auth_ssid_len) {
54941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		params.ssid = drv->auth_ssid;
54951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		params.ssid_len = drv->auth_ssid_len;
54961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
54971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
54981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	params.ie = drv->auth_ie;
54991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	params.ie_len = drv->auth_ie_len;
55001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
55011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	for (i = 0; i < 4; i++) {
55021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (drv->auth_wep_key_len[i]) {
55031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			params.wep_key[i] = drv->auth_wep_key[i];
55041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			params.wep_key_len[i] = drv->auth_wep_key_len[i];
55051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		}
55061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
55071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
55081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->retry_auth = 1;
55091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return wpa_driver_nl80211_authenticate(bss, &params);
55101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
55111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
55121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
55138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct phy_info_arg {
55148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 *num_modes;
55158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_hw_modes *modes;
55162f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	int last_mode, last_chan_idx;
55178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
55188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
55192f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidtstatic void phy_info_ht_capa(struct hostapd_hw_modes *mode, struct nlattr *capa,
55202f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			     struct nlattr *ampdu_factor,
55212f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			     struct nlattr *ampdu_density,
55222f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			     struct nlattr *mcs_set)
55238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
55242f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (capa)
55252f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		mode->ht_capab = nla_get_u16(capa);
55268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
55272f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (ampdu_factor)
55282f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		mode->a_mpdu_params |= nla_get_u8(ampdu_factor) & 0x03;
55298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
55302f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (ampdu_density)
55312f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		mode->a_mpdu_params |= nla_get_u8(ampdu_density) << 2;
55322f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
55332f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (mcs_set && nla_len(mcs_set) >= 16) {
55342f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		u8 *mcs;
55352f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		mcs = nla_data(mcs_set);
55362f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		os_memcpy(mode->mcs_set, mcs, 16);
55372f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
55382f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt}
55392f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
55402f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
55412f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidtstatic void phy_info_vht_capa(struct hostapd_hw_modes *mode,
55422f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			      struct nlattr *capa,
55432f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			      struct nlattr *mcs_set)
55442f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt{
55452f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (capa)
55462f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		mode->vht_capab = nla_get_u32(capa);
55472f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
55482f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (mcs_set && nla_len(mcs_set) >= 8) {
55492f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		u8 *mcs;
55502f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		mcs = nla_data(mcs_set);
55512f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		os_memcpy(mode->vht_mcs_set, mcs, 8);
55522f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
55532f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt}
55542f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
55552f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
55562f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidtstatic void phy_info_freq(struct hostapd_hw_modes *mode,
55572f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			  struct hostapd_channel_data *chan,
55582f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			  struct nlattr *tb_freq[])
55592f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt{
55604b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	u8 channel;
55612f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
55622f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	chan->flag = 0;
55634b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt	if (ieee80211_freq_to_chan(chan->freq, &channel) != NUM_HOSTAPD_MODES)
55644b06059785b935dd1f4f09314e4e12c417d2c6a4Dmitry Shmidt		chan->chan = channel;
55652f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
55662f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
55672f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		chan->flag |= HOSTAPD_CHAN_DISABLED;
55682f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
55692f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		chan->flag |= HOSTAPD_CHAN_PASSIVE_SCAN;
55702f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
55712f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		chan->flag |= HOSTAPD_CHAN_NO_IBSS;
55722f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
55732f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		chan->flag |= HOSTAPD_CHAN_RADAR;
55742f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
55752f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
55762f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	    !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
55772f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		chan->max_tx_power = nla_get_u32(
55782f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
5579ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
5580ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		enum nl80211_dfs_state state =
5581ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt			nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
5582ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
5583ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		switch (state) {
5584ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		case NL80211_DFS_USABLE:
5585ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt			chan->flag |= HOSTAPD_CHAN_DFS_USABLE;
5586ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt			break;
5587ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		case NL80211_DFS_AVAILABLE:
5588ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt			chan->flag |= HOSTAPD_CHAN_DFS_AVAILABLE;
5589ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt			break;
5590ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		case NL80211_DFS_UNAVAILABLE:
5591ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt			chan->flag |= HOSTAPD_CHAN_DFS_UNAVAILABLE;
5592ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt			break;
5593ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		}
5594ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	}
55952f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt}
55962f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
55972f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
55982f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidtstatic int phy_info_freqs(struct phy_info_arg *phy_info,
55992f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			  struct hostapd_hw_modes *mode, struct nlattr *tb)
56002f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt{
56018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
56028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
56038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
56048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
56058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
56068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
56078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
5608ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		[NL80211_FREQUENCY_ATTR_DFS_STATE] = { .type = NLA_U32 },
56098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
56102f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	int new_channels = 0;
56112f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct hostapd_channel_data *channel;
56122f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
56138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *nl_freq;
56142f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	int rem_freq, idx;
56158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56162f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (tb == NULL)
56172f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		return NL_OK;
56188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56192f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	nla_for_each_nested(nl_freq, tb, rem_freq) {
56202f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
56212f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			  nla_data(nl_freq), nla_len(nl_freq), freq_policy);
56222f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
56232f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			continue;
56242f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		new_channels++;
56252f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
56262f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
56272f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	channel = os_realloc_array(mode->channels,
56282f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt				   mode->num_channels + new_channels,
56292f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt				   sizeof(struct hostapd_channel_data));
56302f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (!channel)
56318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
56328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56332f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	mode->channels = channel;
56342f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	mode->num_channels += new_channels;
56358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56362f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	idx = phy_info->last_chan_idx;
56378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56382f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	nla_for_each_nested(nl_freq, tb, rem_freq) {
56392f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
56402f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			  nla_data(nl_freq), nla_len(nl_freq), freq_policy);
56412f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
56422f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			continue;
56432f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		phy_info_freq(mode, &mode->channels[idx], tb_freq);
56442f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		idx++;
56452f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
56462f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	phy_info->last_chan_idx = idx;
56478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56482f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	return NL_OK;
56492f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt}
56508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56522f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidtstatic int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb)
56532f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt{
56542f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
56552f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		[NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
56562f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] =
56572f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		{ .type = NLA_FLAG },
56582f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	};
56592f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
56602f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct nlattr *nl_rate;
56612f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	int rem_rate, idx;
56628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56632f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (tb == NULL)
56642f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		return NL_OK;
56658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56662f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	nla_for_each_nested(nl_rate, tb, rem_rate) {
56672f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
56682f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			  nla_data(nl_rate), nla_len(nl_rate),
56692f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			  rate_policy);
56702f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
56712f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			continue;
56722f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		mode->num_rates++;
56732f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
56748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56752f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	mode->rates = os_calloc(mode->num_rates, sizeof(int));
56762f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (!mode->rates)
56772f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		return NL_SKIP;
567804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
56792f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	idx = 0;
568004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
56812f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	nla_for_each_nested(nl_rate, tb, rem_rate) {
56822f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
56832f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			  nla_data(nl_rate), nla_len(nl_rate),
56842f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			  rate_policy);
56852f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
56862f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			continue;
56872f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		mode->rates[idx] = nla_get_u32(
56882f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			tb_rate[NL80211_BITRATE_ATTR_RATE]);
56892f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		idx++;
56902f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
56918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56922f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	return NL_OK;
56932f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt}
56948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56962f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidtstatic int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
56972f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt{
56982f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
56992f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct hostapd_hw_modes *mode;
57002f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	int ret;
57018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57022f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (phy_info->last_mode != nl_band->nla_type) {
57032f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		mode = os_realloc_array(phy_info->modes,
57042f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt					*phy_info->num_modes + 1,
57052f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt					sizeof(*mode));
57062f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		if (!mode)
57078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NL_SKIP;
57082f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		phy_info->modes = mode;
57098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57102f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		mode = &phy_info->modes[*(phy_info->num_modes)];
57112f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		os_memset(mode, 0, sizeof(*mode));
57122f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		mode->mode = NUM_HOSTAPD_MODES;
5713c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN |
5714c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt			HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN;
5715c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
5716c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		/*
5717c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		 * Unsupported VHT MCS stream is defined as value 3, so the VHT
5718c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		 * MCS RX/TX map must be initialized with 0xffff to mark all 8
5719c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		 * possible streams as unsupported. This will be overridden if
5720c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		 * driver advertises VHT support.
5721c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		 */
5722c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		mode->vht_mcs_set[0] = 0xff;
5723c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		mode->vht_mcs_set[1] = 0xff;
5724c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		mode->vht_mcs_set[4] = 0xff;
5725c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		mode->vht_mcs_set[5] = 0xff;
5726c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
57272f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		*(phy_info->num_modes) += 1;
57282f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		phy_info->last_mode = nl_band->nla_type;
57292f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		phy_info->last_chan_idx = 0;
57302f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	} else
57312f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		mode = &phy_info->modes[*(phy_info->num_modes) - 1];
57322f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
57332f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
57342f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		  nla_len(nl_band), NULL);
57352f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
57362f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	phy_info_ht_capa(mode, tb_band[NL80211_BAND_ATTR_HT_CAPA],
57372f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			 tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR],
57382f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			 tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY],
57392f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			 tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
57402f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA],
57412f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			  tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
57422f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	ret = phy_info_freqs(phy_info, mode, tb_band[NL80211_BAND_ATTR_FREQS]);
57432f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (ret != NL_OK)
57442f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		return ret;
57452f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
57462f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (ret != NL_OK)
57472f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		return ret;
57488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57492f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	return NL_OK;
57502f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt}
57518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57532f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidtstatic int phy_info_handler(struct nl_msg *msg, void *arg)
57542f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt{
57552f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
57562f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
57572f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct phy_info_arg *phy_info = arg;
57582f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	struct nlattr *nl_band;
57592f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	int rem_band;
57602f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
57612f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
57622f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
57632f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
57642f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
57652f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		return NL_SKIP;
57662f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
57672f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band)
57682f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	{
57692f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		int res = phy_info_band(phy_info, nl_band);
57702f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		if (res != NL_OK)
57712f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			return res;
57728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
57738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
57758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
57768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57772f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
57788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct hostapd_hw_modes *
57790ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidtwpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
57800ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt				     u16 *num_modes)
57818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
57828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 m;
57838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
57848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i, mode11g_idx = -1;
57858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57860ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	/* heuristic to set up modes */
57870ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	for (m = 0; m < *num_modes; m++) {
57880ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		if (!modes[m].num_channels)
57890ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt			continue;
57900ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		if (modes[m].channels[0].freq < 4000) {
57910ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt			modes[m].mode = HOSTAPD_MODE_IEEE80211B;
57920ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt			for (i = 0; i < modes[m].num_rates; i++) {
57930ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt				if (modes[m].rates[i] > 200) {
57940ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt					modes[m].mode = HOSTAPD_MODE_IEEE80211G;
57950ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt					break;
57960ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt				}
57970ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt			}
57980ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		} else if (modes[m].channels[0].freq > 50000)
57990ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt			modes[m].mode = HOSTAPD_MODE_IEEE80211AD;
58000ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		else
58010ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt			modes[m].mode = HOSTAPD_MODE_IEEE80211A;
58020ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	}
58030ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt
58048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* If only 802.11g mode is included, use it to construct matching
58058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * 802.11b mode data. */
58068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (m = 0; m < *num_modes; m++) {
58088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (modes[m].mode == HOSTAPD_MODE_IEEE80211B)
58098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return modes; /* 802.11b already included */
58108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (modes[m].mode == HOSTAPD_MODE_IEEE80211G)
58118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			mode11g_idx = m;
58128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
58138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (mode11g_idx < 0)
58158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return modes; /* 2.4 GHz band not supported at all */
58168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
581761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes));
58188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nmodes == NULL)
58198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return modes; /* Could not add 802.11b mode */
58208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mode = &nmodes[*num_modes];
58228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(mode, 0, sizeof(*mode));
58238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	(*num_modes)++;
58248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	modes = nmodes;
58258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mode->mode = HOSTAPD_MODE_IEEE80211B;
58278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mode11g = &modes[mode11g_idx];
58298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mode->num_channels = mode11g->num_channels;
58308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mode->channels = os_malloc(mode11g->num_channels *
58318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   sizeof(struct hostapd_channel_data));
58328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (mode->channels == NULL) {
58338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		(*num_modes)--;
58348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return modes; /* Could not add 802.11b mode */
58358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
58368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(mode->channels, mode11g->channels,
58378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  mode11g->num_channels * sizeof(struct hostapd_channel_data));
58388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mode->num_rates = 0;
58408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mode->rates = os_malloc(4 * sizeof(int));
58418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (mode->rates == NULL) {
58428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(mode->channels);
58438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		(*num_modes)--;
58448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return modes; /* Could not add 802.11b mode */
58458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
58468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < mode11g->num_rates; i++) {
58488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 &&
58498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    mode11g->rates[i] != 55 && mode11g->rates[i] != 110)
58508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
58518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mode->rates[mode->num_rates] = mode11g->rates[i];
58528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mode->num_rates++;
58538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (mode->num_rates == 4)
58548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
58558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
58568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (mode->num_rates == 0) {
58588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(mode->channels);
58598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(mode->rates);
58608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		(*num_modes)--;
58618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return modes; /* No 802.11b rates */
58628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
58638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g "
58658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "information");
58668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return modes;
58688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
58698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_set_ht40_mode(struct hostapd_hw_modes *mode, int start,
58728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  int end)
58738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
58748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int c;
58758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (c = 0; c < mode->num_channels; c++) {
58778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct hostapd_channel_data *chan = &mode->channels[c];
58788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (chan->freq - 10 >= start && chan->freq + 10 <= end)
58798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			chan->flag |= HOSTAPD_CHAN_HT40;
58808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
58818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
58828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start,
58858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      int end)
58868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
58878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int c;
58888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (c = 0; c < mode->num_channels; c++) {
58908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct hostapd_channel_data *chan = &mode->channels[c];
58918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!(chan->flag & HOSTAPD_CHAN_HT40))
58928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
58938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (chan->freq - 30 >= start && chan->freq - 10 <= end)
58948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			chan->flag |= HOSTAPD_CHAN_HT40MINUS;
58958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (chan->freq + 10 >= start && chan->freq + 30 <= end)
58968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			chan->flag |= HOSTAPD_CHAN_HT40PLUS;
58978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
58988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
58998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_reg_rule_ht40(struct nlattr *tb[],
59028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  struct phy_info_arg *results)
59038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
59048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 start, end, max_bw;
59058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 m;
59068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
59088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
59098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
59108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
59118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
59138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
59148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
59158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz",
59178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   start, end, max_bw);
59188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (max_bw < 40)
59198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
59208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (m = 0; m < *results->num_modes; m++) {
59228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!(results->modes[m].ht_capab &
59238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
59248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
59258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_set_ht40_mode(&results->modes[m], start, end);
59268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
59278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
59288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_reg_rule_sec(struct nlattr *tb[],
59318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 struct phy_info_arg *results)
59328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
59338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 start, end, max_bw;
59348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 m;
59358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
59378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
59388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
59398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
59408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
59428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
59438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
59448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (max_bw < 20)
59468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
59478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (m = 0; m < *results->num_modes; m++) {
59498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!(results->modes[m].ht_capab &
59508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
59518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
59528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_set_ht40_mode_sec(&results->modes[m], start, end);
59538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
59548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
59558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_get_reg(struct nl_msg *msg, void *arg)
59588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
59598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct phy_info_arg *results = arg;
59608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
59618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
59628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *nl_rule;
59638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1];
59648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int rem_rule;
59658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
59668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
59678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
59688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
59698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
59708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
59718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
59728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
59738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
59758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
59768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!tb_msg[NL80211_ATTR_REG_ALPHA2] ||
59778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    !tb_msg[NL80211_ATTR_REG_RULES]) {
59788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: No regulatory information "
59798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "available");
59808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
59818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
59828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s",
59848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]));
59858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
59878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
59888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
59898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  nla_data(nl_rule), nla_len(nl_rule), reg_policy);
59908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_reg_rule_ht40(tb_rule, results);
59918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
59928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
59948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
59958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
59968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  nla_data(nl_rule), nla_len(nl_rule), reg_policy);
59978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_reg_rule_sec(tb_rule, results);
59988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
59998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
60018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
60028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_set_ht40_flags(struct wpa_driver_nl80211_data *drv,
60058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  struct phy_info_arg *results)
60068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
60078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
60088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
60108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
60118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
60128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
60148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
60158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
60168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct hostapd_hw_modes *
60198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtwpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
60208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
60212f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	u32 feat;
60228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
60238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
60248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
60258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct phy_info_arg result = {
60268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		.num_modes = num_modes,
60278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		.modes = NULL,
60282f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		.last_mode = -1,
60298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
60308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*num_modes = 0;
60328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*flags = 0;
60338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
60358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
60368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
60378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60382f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	feat = get_nl80211_protocol_features(drv);
60392f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
60402f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_WIPHY);
60412f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	else
60422f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
60438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60442f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
60458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
60468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
60488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_set_ht40_flags(drv, &result);
60490ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		return wpa_driver_nl80211_postprocess_modes(result.modes,
60500ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt							    num_modes);
60518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
60521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
60538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
60541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
60558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
60568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
60578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int wpa_driver_nl80211_send_mntr(struct wpa_driver_nl80211_data *drv,
60601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					const void *data, size_t len,
60611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					int encrypt, int noack)
60628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
60638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	__u8 rtap_hdr[] = {
60648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x00, 0x00, /* radiotap version */
60658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x0e, 0x00, /* radiotap length */
60668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
60678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
60688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x00,       /* padding */
60698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x00, 0x00, /* RX and TX flags to indicate that */
60708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x00, 0x00, /* this is the injected frame directly */
60718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
60728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct iovec iov[2] = {
60738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		{
60748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			.iov_base = &rtap_hdr,
60758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			.iov_len = sizeof(rtap_hdr),
60768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		},
60778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		{
60788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			.iov_base = (void *) data,
60798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			.iov_len = len,
60808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
60818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
60828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct msghdr msg = {
60838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		.msg_name = NULL,
60848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		.msg_namelen = 0,
60858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		.msg_iov = iov,
60868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		.msg_iovlen = 2,
60878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		.msg_control = NULL,
60888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		.msg_controllen = 0,
60898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		.msg_flags = 0,
60908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
60918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res;
60921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u16 txflags = 0;
60938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encrypt)
60958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
60968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6097c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	if (drv->monitor_sock < 0) {
6098c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: No monitor socket available "
6099c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt			   "for %s", __func__);
6100c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		return -1;
6101c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	}
6102c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt
61031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (noack)
61041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
6105d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	WPA_PUT_LE16(&rtap_hdr[12], txflags);
61061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
61078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = sendmsg(drv->monitor_sock, &msg, 0);
61088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res < 0) {
61098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
61108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
61118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
61128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
61138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
61148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
61171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					 const void *data, size_t len,
6118c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					 int encrypt, int noack,
6119c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					 unsigned int freq, int no_cck,
6120c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					 int offchanok, unsigned int wait_time)
61211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
61221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
61231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u64 cookie;
61241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6125c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (freq == 0)
6126c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		freq = bss->freq;
6127c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
61281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->use_monitor)
61291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return wpa_driver_nl80211_send_mntr(drv, data, len,
61301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt						    encrypt, noack);
61311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6132c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	return nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
6133c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				      &cookie, no_cck, noack, offchanok);
61341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
61351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
61361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
61374b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
61384b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					size_t data_len, int noack,
61394b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					unsigned int freq, int no_cck,
61404b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					int offchanok,
61414b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					unsigned int wait_time)
61428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
61438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
61448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee80211_mgmt *mgmt;
61458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int encrypt = 1;
61468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 fc;
61478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt = (struct ieee80211_mgmt *) data;
61498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	fc = le_to_host16(mgmt->frame_control);
61501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
615134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if ((is_sta_interface(drv->nlmode) ||
615234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	     drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) &&
61538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
61548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
61558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
61568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * The use of last_mgmt_freq is a bit of a hack,
61578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * but it works due to the single-threaded nature
61588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * of wpa_supplicant.
61598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
6160c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		if (freq == 0)
6161c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			freq = drv->last_mgmt_freq;
6162c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		return nl80211_send_frame_cmd(bss, freq, 0,
61631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					      data, data_len, NULL, 1, noack,
61641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					      1);
61658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
61661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
61671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
6168c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		if (freq == 0)
6169c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			freq = bss->freq;
617004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return nl80211_send_frame_cmd(bss, freq,
617104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					      (int) freq == bss->freq ? 0 :
617204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt					      wait_time,
6173c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					      data, data_len,
6174c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					      &drv->send_action_cookie,
6175c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					      no_cck, noack, offchanok);
61766e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidt	}
6177b638fe75d3cb9d21c67386173f10afe65053cc4dDmitry Shmidt
61788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
61798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
61808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
61818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Only one of the authentication frame types is encrypted.
61828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * In order for static WEP encryption to work properly (i.e.,
61838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * to not encrypt the frame), we need to tell mac80211 about
61848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * the frames that must not be encrypted.
61858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
61868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
61878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction);
61888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
61898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			encrypt = 0;
61908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
61911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
61921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
6193c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					     noack, freq, no_cck, offchanok,
6194c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					     wait_time);
6195c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt}
6196c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
6197c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
61981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
61991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   int slot, int ht_opmode, int ap_isolate,
62001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   int *basic_rates)
62011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
62021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
62031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_msg *msg;
62041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
62051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = nlmsg_alloc();
62061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!msg)
62071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -ENOMEM;
62081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
62091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_BSS);
62101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
62111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (cts >= 0)
62121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts);
62131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (preamble >= 0)
62141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble);
62151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (slot >= 0)
62161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot);
62171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ht_opmode >= 0)
62181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode);
62191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ap_isolate >= 0)
62201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate);
62211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
62221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (basic_rates) {
62231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		u8 rates[NL80211_MAX_SUPP_RATES];
62241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		u8 rates_len = 0;
62251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		int i;
62261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
62271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0;
62281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		     i++)
62291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			rates[rates_len++] = basic_rates[i] / 5;
62301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
62311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
62321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
62331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
62341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
62351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
62361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
62371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt nla_put_failure:
62381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
62391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return -ENOBUFS;
62408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
62418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62438bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidtstatic int wpa_driver_nl80211_set_acl(void *priv,
62448bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt				      struct hostapd_acl_params *params)
62458bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt{
62468bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	struct i802_bss *bss = priv;
62478bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
62488bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	struct nl_msg *msg;
62498bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	struct nlattr *acl;
62508bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	unsigned int i;
62518bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	int ret = 0;
62528bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
62538bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	if (!(drv->capa.max_acl_mac_addrs))
62548bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		return -ENOTSUP;
62558bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
62568bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	if (params->num_mac_acl > drv->capa.max_acl_mac_addrs)
62578bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		return -ENOTSUP;
62588bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
62598bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	msg = nlmsg_alloc();
62608bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	if (!msg)
62618bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		return -ENOMEM;
62628bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
62638bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)",
62648bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		   params->acl_policy ? "Accept" : "Deny", params->num_mac_acl);
62658bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
62668bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_MAC_ACL);
62678bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
62688bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
62698bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
62708bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ?
62718bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		    NL80211_ACL_POLICY_DENY_UNLESS_LISTED :
62728bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		    NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED);
62738bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
62748bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	acl = nla_nest_start(msg, NL80211_ATTR_MAC_ADDRS);
62758bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	if (acl == NULL)
62768bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		goto nla_put_failure;
62778bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
62788bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	for (i = 0; i < params->num_mac_acl; i++)
62798bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		NLA_PUT(msg, i + 1, ETH_ALEN, params->mac_acl[i].addr);
62808bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
62818bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	nla_nest_end(msg, acl);
62828bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
62838bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
62848bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	msg = NULL;
62858bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	if (ret) {
62868bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Failed to set MAC ACL: %d (%s)",
62878bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt			   ret, strerror(-ret));
62888bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	}
62898bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
62908bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidtnla_put_failure:
62918bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	nlmsg_free(msg);
62928bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
62938bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	return ret;
62948bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt}
62958bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
62968bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
62971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int wpa_driver_nl80211_set_ap(void *priv,
62981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				     struct wpa_driver_ap_params *params)
62998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
63008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
63018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
63028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
63038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 cmd = NL80211_CMD_NEW_BEACON;
63048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
63058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int beacon_set;
63068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifindex = if_nametoindex(bss->ifname);
63071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int num_suites;
63081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u32 suites[10];
63091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u32 ver;
63101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
63116e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidt	beacon_set = bss->beacon_set;
63128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
63148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
63158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
63168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
63188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   beacon_set);
63198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (beacon_set)
63208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cmd = NL80211_CMD_SET_BEACON;
63218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, cmd);
63230ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "nl80211: Beacon head",
63240ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		    params->head, params->head_len);
63251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head);
63260ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_hexdump(MSG_DEBUG, "nl80211: Beacon tail",
63270ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		    params->tail, params->tail_len);
63281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail);
63290ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", ifindex);
63308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
63310ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int);
63321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int);
63330ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
63341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period);
63350ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid",
63360ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt			  params->ssid, params->ssid_len);
63371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
63381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		params->ssid);
63390ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	if (params->proberesp && params->proberesp_len) {
63400ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "nl80211: proberesp (offload)",
63410ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt			    params->proberesp, params->proberesp_len);
63421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
63431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			params->proberesp);
63440ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	}
63451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	switch (params->hide_ssid) {
63461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NO_SSID_HIDING:
63470ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: hidden SSID not in use");
63481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
63491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    NL80211_HIDDEN_SSID_NOT_IN_USE);
63501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
63511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case HIDDEN_SSID_ZERO_LEN:
63520ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero len");
63531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
63541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    NL80211_HIDDEN_SSID_ZERO_LEN);
63551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
63561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case HIDDEN_SSID_ZERO_CONTENTS:
63570ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero contents");
63581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
63591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    NL80211_HIDDEN_SSID_ZERO_CONTENTS);
63601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
63611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
63620ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: privacy=%d", params->privacy);
63631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->privacy)
63641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
63650ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: auth_algs=0x%x", params->auth_algs);
63661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
63671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
63681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		/* Leave out the attribute */
63691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else if (params->auth_algs & WPA_AUTH_ALG_SHARED)
63701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
63711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    NL80211_AUTHTYPE_SHARED_KEY);
63721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	else
63731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
63741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    NL80211_AUTHTYPE_OPEN_SYSTEM);
63751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
63760ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: wpa_version=0x%x", params->wpa_version);
63771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ver = 0;
63781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->wpa_version & WPA_PROTO_WPA)
63791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		ver |= NL80211_WPA_VERSION_1;
63801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->wpa_version & WPA_PROTO_RSN)
63811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		ver |= NL80211_WPA_VERSION_2;
63821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ver)
63831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
63841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
63850ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
63860ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		   params->key_mgmt_suites);
63871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	num_suites = 0;
63881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
63891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		suites[num_suites++] = WLAN_AKM_SUITE_8021X;
63901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK)
63911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		suites[num_suites++] = WLAN_AKM_SUITE_PSK;
63921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (num_suites) {
63931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_AKM_SUITES,
63941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			num_suites * sizeof(u32), suites);
63951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
63961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
63971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X &&
63981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40))
63991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT);
64001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
64010ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
64020ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		   params->pairwise_ciphers);
64031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	num_suites = 0;
64041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
64051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
640661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (params->pairwise_ciphers & WPA_CIPHER_GCMP)
640761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		suites[num_suites++] = WLAN_CIPHER_SUITE_GCMP;
64081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->pairwise_ciphers & WPA_CIPHER_TKIP)
64091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP;
64101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->pairwise_ciphers & WPA_CIPHER_WEP104)
64111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104;
64121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->pairwise_ciphers & WPA_CIPHER_WEP40)
64131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40;
64141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (num_suites) {
64151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
64161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			num_suites * sizeof(u32), suites);
64171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
64181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
64190ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x",
64200ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		   params->group_cipher);
64211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	switch (params->group_cipher) {
64221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case WPA_CIPHER_CCMP:
64231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
64241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    WLAN_CIPHER_SUITE_CCMP);
64251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
642661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	case WPA_CIPHER_GCMP:
642761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
642861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			    WLAN_CIPHER_SUITE_GCMP);
642961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		break;
64301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case WPA_CIPHER_TKIP:
64311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
64321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    WLAN_CIPHER_SUITE_TKIP);
64331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
64341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case WPA_CIPHER_WEP104:
64351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
64361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    WLAN_CIPHER_SUITE_WEP104);
64371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
64381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case WPA_CIPHER_WEP40:
64391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
64401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    WLAN_CIPHER_SUITE_WEP40);
64411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
64421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
64431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
64441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->beacon_ies) {
64450ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
64460ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt				params->beacon_ies);
64471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies),
64481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpabuf_head(params->beacon_ies));
64491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
64501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->proberesp_ies) {
64510ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		wpa_hexdump_buf(MSG_DEBUG, "nl80211: proberesp_ies",
64520ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt				params->proberesp_ies);
64531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
64541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpabuf_len(params->proberesp_ies),
64551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpabuf_head(params->proberesp_ies));
64561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
64571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->assocresp_ies) {
64580ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		wpa_hexdump_buf(MSG_DEBUG, "nl80211: assocresp_ies",
64590ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt				params->assocresp_ies);
64601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP,
64611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpabuf_len(params->assocresp_ies),
64621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpabuf_head(params->assocresp_ies));
64631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
64648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
646504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)  {
64660ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: ap_max_inactivity=%d",
64670ccb66edb8d2a0a397320ace3ec2a03fb0d00d5fDmitry Shmidt			   params->ap_max_inactivity);
646804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		NLA_PUT_U16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
646904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			    params->ap_max_inactivity);
647004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
647104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
64728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
64738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
64748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
64758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ret, strerror(-ret));
64768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
64778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->beacon_set = 1;
64781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_set_bss(bss, params->cts_protect, params->preamble,
64791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				params->short_slot_time, params->ht_opmode,
64801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				params->isolate, params->basic_rates);
64818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
64828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
64838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
64841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
64858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
64868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
64878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
6490a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				       struct hostapd_freq_params *freq)
64918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
64921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
64938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
64948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
64958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6496a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d,"
6497a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		   " bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
6498a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		   freq->freq, freq->ht_enabled, freq->vht_enabled,
6499a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		   freq->bandwidth, freq->center_freq1, freq->center_freq2);
65008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
65018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
65028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
65038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
65058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
6507a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
6508a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (freq->vht_enabled) {
6509a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		switch (freq->bandwidth) {
6510a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		case 20:
6511a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
6512a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				    NL80211_CHAN_WIDTH_20);
6513a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			break;
6514a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		case 40:
6515a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
6516a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				    NL80211_CHAN_WIDTH_40);
6517a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			break;
6518a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		case 80:
6519a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			if (freq->center_freq2)
6520a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
6521a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt					    NL80211_CHAN_WIDTH_80P80);
6522a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			else
6523a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
6524a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt					    NL80211_CHAN_WIDTH_80);
6525a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			break;
6526a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		case 160:
6527a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
6528a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				    NL80211_CHAN_WIDTH_160);
6529a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			break;
6530a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		default:
6531a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			return -1;
6532a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		}
6533a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1);
6534a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		if (freq->center_freq2)
6535a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2,
6536a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt				    freq->center_freq2);
6537a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	} else if (freq->ht_enabled) {
6538a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		switch (freq->sec_channel_offset) {
65398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case -1:
65408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
65418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    NL80211_CHAN_HT40MINUS);
65428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
65438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case 1:
65448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
65458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    NL80211_CHAN_HT40PLUS);
65468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
65478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
65488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
65498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    NL80211_CHAN_HT20);
65508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
65518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
65528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
65538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
65551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
65561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ret == 0) {
6557a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		bss->freq = freq->freq;
65588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
65591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
65608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
6561a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		   "%d (%s)", freq->freq, ret, strerror(-ret));
65628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
65631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
65648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
65658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
65668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic u32 sta_flags_nl80211(int flags)
65698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
65701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u32 f = 0;
65718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (flags & WPA_STA_AUTHORIZED)
65731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
65741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (flags & WPA_STA_WMM)
65751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		f |= BIT(NL80211_STA_FLAG_WME);
65761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (flags & WPA_STA_SHORT_PREAMBLE)
65771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
65781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (flags & WPA_STA_MFP)
65791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		f |= BIT(NL80211_STA_FLAG_MFP);
65801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (flags & WPA_STA_TDLS_PEER)
65811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
65821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
65831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return f;
65841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
65851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
65861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
65871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int wpa_driver_nl80211_sta_add(void *priv,
65881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				      struct hostapd_sta_add_params *params)
65891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
65901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct i802_bss *bss = priv;
65911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
65928da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	struct nl_msg *msg;
65931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl80211_sta_flag_update upd;
65941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int ret = -ENOBUFS;
65951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
65961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if ((params->flags & WPA_STA_TDLS_PEER) &&
65971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
65981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -EOPNOTSUPP;
65991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
66001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = nlmsg_alloc();
66011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!msg)
66021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -ENOMEM;
66031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6604f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR,
6605f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		   params->set ? "Set" : "Add", MAC2STR(params->addr));
66061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION :
66071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    NL80211_CMD_NEW_STATION);
66088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
66098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
66108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
66118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
66128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		params->supp_rates);
6613f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "  * supported rates", params->supp_rates,
6614f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		    params->supp_rates_len);
66151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!params->set) {
661651b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt		if (params->aid) {
661751b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt			wpa_printf(MSG_DEBUG, "  * aid=%u", params->aid);
661851b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt			NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
661951b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt		} else {
662051b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt			/*
662151b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt			 * cfg80211 validates that AID is non-zero, so we have
662251b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt			 * to make this a non-zero value for the TDLS case where
662351b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt			 * a dummy STA entry is used for now.
662451b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt			 */
662551b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt			wpa_printf(MSG_DEBUG, "  * aid=1 (TDLS workaround)");
662651b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt			NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, 1);
662751b6ea882f234c14cd1fe1332a3840cf61fafccaDmitry Shmidt		}
6628f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * listen_interval=%u",
6629f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			   params->listen_interval);
66301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
66311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    params->listen_interval);
66328bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	} else if (params->aid && (params->flags & WPA_STA_TDLS_PEER)) {
66338bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * peer_aid=%u", params->aid);
66348bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		NLA_PUT_U16(msg, NL80211_ATTR_PEER_AID, params->aid);
66351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
66368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->ht_capabilities) {
6637f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		wpa_hexdump(MSG_DEBUG, "  * ht_capabilities",
6638f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			    (u8 *) params->ht_capabilities,
6639f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			    sizeof(*params->ht_capabilities));
66408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
66418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			sizeof(*params->ht_capabilities),
66428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->ht_capabilities);
66438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
66448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6645a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (params->vht_capabilities) {
6646f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		wpa_hexdump(MSG_DEBUG, "  * vht_capabilities",
6647f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			    (u8 *) params->vht_capabilities,
6648f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			    sizeof(*params->vht_capabilities));
6649a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY,
6650a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			sizeof(*params->vht_capabilities),
6651a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			params->vht_capabilities);
6652a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
6653a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
6654f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	wpa_printf(MSG_DEBUG, "  * capability=0x%x", params->capability);
6655f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	NLA_PUT_U16(msg, NL80211_ATTR_STA_CAPABILITY, params->capability);
6656f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
6657f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (params->ext_capab) {
6658f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		wpa_hexdump(MSG_DEBUG, "  * ext_capab",
6659f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			    params->ext_capab, params->ext_capab_len);
6660f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_STA_EXT_CAPABILITY,
6661f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			params->ext_capab_len, params->ext_capab);
6662f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	}
6663f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
66641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memset(&upd, 0, sizeof(upd));
66651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	upd.mask = sta_flags_nl80211(params->flags);
66661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	upd.set = upd.mask;
6667f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	wpa_printf(MSG_DEBUG, "  * flags set=0x%x mask=0x%x",
6668f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		   upd.set, upd.mask);
66691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
66701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
66711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->flags & WPA_STA_WMM) {
66728da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		struct nlattr *wme = nla_nest_start(msg, NL80211_ATTR_STA_WME);
66738da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt
66741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (!wme)
66751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			goto nla_put_failure;
66761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
6677f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * qosinfo=0x%x", params->qosinfo);
66788da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		NLA_PUT_U8(msg, NL80211_STA_WME_UAPSD_QUEUES,
66791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
66808da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		NLA_PUT_U8(msg, NL80211_STA_WME_MAX_SP,
6681f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt				(params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
66821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				WMM_QOSINFO_STA_SP_MASK);
66838da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		nla_nest_end(msg, wme);
66841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
66851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
66868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
66871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
66888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret)
66891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
66901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "result: %d (%s)", params->set ? "SET" : "NEW", ret,
66911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   strerror(-ret));
66928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == -EEXIST)
66938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = 0;
66948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
66951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
66968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
66978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
66988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
66998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
67004b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr)
67018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
67028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
67038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
67048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
67058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
67068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
67078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
67088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
67098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
67101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
67118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
67128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
67138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    if_nametoindex(bss->ifname));
67148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
67158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
67168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
6717b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR
6718b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		   " --> %d (%s)",
6719b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		   bss->ifname, MAC2STR(addr), ret, strerror(-ret));
67208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == -ENOENT)
67218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
67228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
67238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
67241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
67258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
67268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
67278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
67288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
67298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
67308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 int ifidx)
67318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
67328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
67338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
67348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
67358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
67368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* stop listening for EAPOL on this interface */
67378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	del_ifidx(drv, ifidx);
67388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
67398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
67408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
67418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
67428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
67431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE);
67448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
67458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
67468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
67478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
67481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
67498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
67501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
67518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
67528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
67538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
67548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
67551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic const char * nl80211_iftype_str(enum nl80211_iftype mode)
67561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
67571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	switch (mode) {
67581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_IFTYPE_ADHOC:
67591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return "ADHOC";
67601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_IFTYPE_STATION:
67611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return "STATION";
67621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_IFTYPE_AP:
67631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return "AP";
6764f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt	case NL80211_IFTYPE_AP_VLAN:
6765f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt		return "AP_VLAN";
6766f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt	case NL80211_IFTYPE_WDS:
6767f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt		return "WDS";
67681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_IFTYPE_MONITOR:
67691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return "MONITOR";
6770f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt	case NL80211_IFTYPE_MESH_POINT:
6771f7e0a9905988e62e4f70fed8b795722abeab719bDmitry Shmidt		return "MESH_POINT";
67721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_IFTYPE_P2P_CLIENT:
67731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return "P2P_CLIENT";
67741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case NL80211_IFTYPE_P2P_GO:
67751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return "P2P_GO";
677634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case NL80211_IFTYPE_P2P_DEVICE:
677734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return "P2P_DEVICE";
67781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	default:
67791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return "unknown";
67801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
67811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
67821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
67831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
67848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
67858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     const char *ifname,
67868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     enum nl80211_iftype iftype,
678734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				     const u8 *addr, int wds,
678834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				     int (*handler)(struct nl_msg *, void *),
678934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				     void *arg)
67908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
67918da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	struct nl_msg *msg;
67928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifidx;
67938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -ENOBUFS;
67948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
67951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)",
67961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   iftype, nl80211_iftype_str(iftype));
67971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
67988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
67998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
68008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
68018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
680334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
680434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		goto nla_put_failure;
68058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
68068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
68078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (iftype == NL80211_IFTYPE_MONITOR) {
68098da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		struct nlattr *flags;
68108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68118da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
68128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!flags)
68138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto nla_put_failure;
68148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68158da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_MNTR_FLAG_COOK_FRAMES);
68168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68178da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		nla_nest_end(msg, flags);
68188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (wds) {
68198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
68208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
68218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
682234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, handler, arg);
68231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
68248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
68258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
68261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nlmsg_free(msg);
68278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
68288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ifname, ret, strerror(-ret));
68298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ret;
68308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
68318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
683234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (iftype == NL80211_IFTYPE_P2P_DEVICE)
683334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return 0;
683434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
68358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ifidx = if_nametoindex(ifname);
68368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
68378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   ifname, ifidx);
68388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ifidx <= 0)
68408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
68418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* start listening for EAPOL on this interface */
68438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	add_ifidx(drv, ifidx);
68448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (addr && iftype != NL80211_IFTYPE_MONITOR &&
68461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) {
68478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_remove_iface(drv, ifidx);
68488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
68498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
68508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ifidx;
68528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
68538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
68568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				const char *ifname, enum nl80211_iftype iftype,
685734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				const u8 *addr, int wds,
685834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				int (*handler)(struct nl_msg *, void *),
685934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				void *arg)
68608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
68618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
68628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
686334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds, handler,
686434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					arg);
68658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* if error occurred and interface exists already */
68678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == -ENFILE && if_nametoindex(ifname)) {
68688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
68698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Try to remove the interface that was already there. */
68718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_remove_iface(drv, if_nametoindex(ifname));
68728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Try to create the interface again */
68748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
687534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt						wds, handler, arg);
68768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
68778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
687834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (ret >= 0 && is_p2p_net_interface(iftype))
68798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_disable_11b_rates(drv, ret, 1);
68808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
68828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
68838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
68868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
68878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee80211_hdr *hdr;
68888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 fc;
68898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
68908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = (struct ieee80211_hdr *) buf;
68928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	fc = le_to_host16(hdr->frame_control);
68938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
68948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
68958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.type = WLAN_FC_GET_TYPE(fc);
68968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
68978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.dst = hdr->addr1;
68988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.data = buf;
68998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.data_len = len;
69008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.ack = ok;
69018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event);
69028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
69038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
69048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
69058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
69068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     u8 *buf, size_t len)
69078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
69081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct ieee80211_hdr *hdr = (void *)buf;
69091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	u16 fc;
69108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
69111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
69121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (len < sizeof(*hdr))
69131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
69141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
69151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	fc = le_to_host16(hdr->frame_control);
69161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
69178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
69181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
69191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	event.rx_from_unknown.addr = hdr->addr2;
69201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) ==
69211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		(WLAN_FC_FROMDS | WLAN_FC_TODS);
69228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
69238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
69248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
69258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
69268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void handle_frame(struct wpa_driver_nl80211_data *drv,
69278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 u8 *buf, size_t len, int datarate, int ssi_signal)
69288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
69298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee80211_hdr *hdr;
69308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 fc;
69318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
69328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
69338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = (struct ieee80211_hdr *) buf;
69348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	fc = le_to_host16(hdr->frame_control);
69358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
69368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (WLAN_FC_GET_TYPE(fc)) {
69378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WLAN_FC_TYPE_MGMT:
69388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memset(&event, 0, sizeof(event));
69398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_mgmt.frame = buf;
69408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_mgmt.frame_len = len;
69418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_mgmt.datarate = datarate;
69428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_mgmt.ssi_signal = ssi_signal;
69438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
69448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
69458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WLAN_FC_TYPE_CTRL:
69468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* can only get here with PS-Poll frames */
69478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "CTRL");
69488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		from_unknown_sta(drv, buf, len);
69498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
69508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WLAN_FC_TYPE_DATA:
69518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		from_unknown_sta(drv, buf, len);
69528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
69538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
69548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
69558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
69568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
69578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
69588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
69598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = eloop_ctx;
69608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int len;
69618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned char buf[3000];
69628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee80211_radiotap_iterator iter;
69638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
69648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int datarate = 0, ssi_signal = 0;
69658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int injected = 0, failed = 0, rxflags = 0;
69668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
69678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len = recv(sock, buf, sizeof(buf), 0);
69688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len < 0) {
69698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		perror("recv");
69708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
69718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
69728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
69738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) {
69748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		printf("received invalid radiotap frame\n");
69758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
69768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
69778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
69788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (1) {
69798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = ieee80211_radiotap_iterator_next(&iter);
69808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret == -ENOENT)
69818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
69828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret) {
69838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			printf("received invalid radiotap frame (%d)\n", ret);
69848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return;
69858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
69868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (iter.this_arg_index) {
69878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IEEE80211_RADIOTAP_FLAGS:
69888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
69898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				len -= 4;
69908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
69918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IEEE80211_RADIOTAP_RX_FLAGS:
69928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			rxflags = 1;
69938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
69948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IEEE80211_RADIOTAP_TX_FLAGS:
69958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			injected = 1;
69968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			failed = le_to_host16((*(uint16_t *) iter.this_arg)) &
69978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					IEEE80211_RADIOTAP_F_TX_FAIL;
69988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
69998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IEEE80211_RADIOTAP_DATA_RETRIES:
70008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
70018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IEEE80211_RADIOTAP_CHANNEL:
70028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* TODO: convert from freq/flags to channel number */
70038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
70048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IEEE80211_RADIOTAP_RATE:
70058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			datarate = *iter.this_arg * 5;
70068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
700704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
700804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			ssi_signal = (s8) *iter.this_arg;
70098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
70108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
70118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
70128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
70138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (rxflags && injected)
70148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
70158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
70168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!injected)
70178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		handle_frame(drv, buf + iter.max_length,
70188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     len - iter.max_length, datarate, ssi_signal);
70198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
70208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		handle_tx_callback(drv->ctx, buf + iter.max_length,
70218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   len - iter.max_length, !failed);
70228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
70238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
70248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
70258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
70268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * we post-process the filter code later and rewrite
70278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * this to the offset to the last instruction
70288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
70298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define PASS	0xFF
70308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define FAIL	0xFE
70318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
70328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct sock_filter msock_filter_insns[] = {
70338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
70348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * do a little-endian load of the radiotap length field
70358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
70368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* load lower byte into A */
70378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_B | BPF_ABS, 2),
70388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* put it into X (== index register) */
70398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_MISC| BPF_TAX, 0),
70408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* load upper byte into A */
70418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_B | BPF_ABS, 3),
70428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* left-shift it by 8 */
70438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8),
70448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* or with X */
70458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0),
70468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* put result into X */
70478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_MISC| BPF_TAX, 0),
70488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
70498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
70508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Allow management frames through, this also gives us those
70518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * management frames that we sent ourselves with status
70528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
70538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* load the lower byte of the IEEE 802.11 frame control field */
70548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_B | BPF_IND, 0),
70558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* mask off frame type and version */
70568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF),
70578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* accept frame if it's both 0, fall through otherwise */
70588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0),
70598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
70608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
70618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * TODO: add a bit to radiotap RX flags that indicates
70628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * that the sending station is not associated, then
70638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * add a filter here that filters on our DA and that flag
70648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * to allow us to deauth frames to that bad station.
70658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *
70668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * For now allow all To DS data frames through.
70678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
70688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* load the IEEE 802.11 frame control field */
70698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_H | BPF_IND, 0),
70708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* mask off frame type, version and DS status */
70718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03),
70728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* accept frame if version 0, type 2 and To DS, fall through otherwise
70738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
70748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0),
70758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
70768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if 0
70778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
70788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * drop non-data frames
70798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
70808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* load the lower byte of the frame control field */
70818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 0),
70828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* mask off QoS bit */
70838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x0c),
70848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* drop non-data frames */
70858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_JUMP(BPF_JMP  | BPF_JEQ | BPF_K, 8, 0, FAIL),
70868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
70878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* load the upper byte of the frame control field */
70888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 1),
70898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* mask off toDS/fromDS */
70908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x03),
70918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* accept WDS frames */
70928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_JUMP(BPF_JMP  | BPF_JEQ | BPF_K, 3, PASS, 0),
70938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
70948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
70958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * add header length to index
70968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
70978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* load the lower byte of the frame control field */
70988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 0),
70998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* mask off QoS bit */
71008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x80),
71018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* right shift it by 6 to give 0 or 2 */
71028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_ALU  | BPF_RSH | BPF_K, 6),
71038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* add data frame header length */
71048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_ALU  | BPF_ADD | BPF_K, 24),
71058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* add index, was start of 802.11 header */
71068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_ALU  | BPF_ADD | BPF_X, 0),
71078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* move to index, now start of LL header */
71088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_MISC | BPF_TAX, 0),
71098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
71108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
71118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Accept empty data frames, we use those for
71128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * polling activity.
71138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
71148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_W | BPF_LEN, 0),
71158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0),
71168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
71178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
71188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Accept EAPOL frames
71198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
71208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_W | BPF_IND, 0),
71218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL),
71228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_W | BPF_IND, 4),
71238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL),
71248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
71258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* keep these last two statements or change the code below */
71268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* return 0 == "DROP" */
71278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_RET | BPF_K, 0),
71288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* return ~0 == "keep all" */
71298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_RET | BPF_K, ~0),
71308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
71318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
71328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct sock_fprog msock_filter = {
71338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.len = sizeof(msock_filter_insns)/sizeof(msock_filter_insns[0]),
71348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.filter = msock_filter_insns,
71358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
71368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
71378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
71388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int add_monitor_filter(int s)
71398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
71408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int idx;
71418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
71428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* rewrite all PASS/FAIL jump offsets */
71438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (idx = 0; idx < msock_filter.len; idx++) {
71448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct sock_filter *insn = &msock_filter_insns[idx];
71458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
71468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (BPF_CLASS(insn->code) == BPF_JMP) {
71478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (insn->code == (BPF_JMP|BPF_JA)) {
71488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				if (insn->k == PASS)
71498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					insn->k = msock_filter.len - idx - 2;
71508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				else if (insn->k == FAIL)
71518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					insn->k = msock_filter.len - idx - 3;
71528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
71538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
71548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (insn->jt == PASS)
71558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				insn->jt = msock_filter.len - idx - 2;
71568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else if (insn->jt == FAIL)
71578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				insn->jt = msock_filter.len - idx - 3;
71588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
71598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (insn->jf == PASS)
71608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				insn->jf = msock_filter.len - idx - 2;
71618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else if (insn->jf == FAIL)
71628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				insn->jf = msock_filter.len - idx - 3;
71638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
71648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
71658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
71668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
71678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       &msock_filter, sizeof(msock_filter))) {
71688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		perror("SO_ATTACH_FILTER");
71698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
71708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
71718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
71728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
71738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
71748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
71758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
71768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_remove_monitor_interface(
71778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv)
71788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
71791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->monitor_refcount--;
71801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->monitor_refcount > 0)
71811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
71821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
71838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->monitor_ifidx >= 0) {
71848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_remove_iface(drv, drv->monitor_ifidx);
71858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->monitor_ifidx = -1;
71868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
71878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->monitor_sock >= 0) {
71888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_unregister_read_sock(drv->monitor_sock);
71898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		close(drv->monitor_sock);
71908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->monitor_sock = -1;
71918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
71928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
71938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
71948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
71958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int
71968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
71978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
71988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char buf[IFNAMSIZ];
71998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sockaddr_ll ll;
72008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int optval;
72018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	socklen_t optlen;
72021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
72031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->monitor_ifidx >= 0) {
72041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		drv->monitor_refcount++;
72051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return 0;
72061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
72071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
72081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (os_strncmp(drv->first_bss.ifname, "p2p-", 4) == 0) {
72091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		/*
72101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * P2P interface name is of the format p2p-%s-%d. For monitor
72111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * interface name corresponding to P2P GO, replace "p2p-" with
72121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * "mon-" to retain the same interface name length and to
72131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * indicate that it is a monitor interface.
72141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 */
72151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss.ifname + 4);
72161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else {
72171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		/* Non-P2P interface with AP functionality. */
72181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
72191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
72201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
72218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf[IFNAMSIZ - 1] = '\0';
72228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
72238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->monitor_ifidx =
72248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
722534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				     0, NULL, NULL);
72268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7227c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	if (drv->monitor_ifidx == -EOPNOTSUPP) {
72281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		/*
72291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * This is backward compatibility for a few versions of
72301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * the kernel only that didn't advertise the right
72311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * attributes for the only driver that then supported
72321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * AP mode w/o monitor -- ath6kl.
72331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 */
7234c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Driver does not support "
7235c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt			   "monitor interface type - try to run without it");
72361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		drv->device_ap_sme = 1;
7237c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	}
7238c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt
72398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->monitor_ifidx < 0)
72408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
72418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
72421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1))
72438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto error;
72448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
72458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memset(&ll, 0, sizeof(ll));
72468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ll.sll_family = AF_PACKET;
72478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ll.sll_ifindex = drv->monitor_ifidx;
72488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
72498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->monitor_sock < 0) {
72508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		perror("socket[PF_PACKET,SOCK_RAW]");
72518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto error;
72528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
72538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
72548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (add_monitor_filter(drv->monitor_sock)) {
72558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "Failed to set socket filter for monitor "
72568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "interface; do filtering in user space");
72578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* This works, but will cost in performance. */
72588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
72598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
72608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
72618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		perror("monitor socket bind");
72628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto error;
72638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
72648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
72658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	optlen = sizeof(optval);
72668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	optval = 20;
72678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (setsockopt
72688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
72698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		perror("Failed to set socket priority");
72708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto error;
72718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
72728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
72738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
72748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     drv, NULL)) {
72758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		printf("Could not register monitor read socket\n");
72768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto error;
72778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
72788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
72798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
72808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt error:
72818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl80211_remove_monitor_interface(drv);
72828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
72838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
72848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
72858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
72861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_setup_ap(struct i802_bss *bss)
72871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
72881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
72891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
72901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Setup AP - device_ap_sme=%d "
72911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   "use_monitor=%d", drv->device_ap_sme, drv->use_monitor);
72921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
72931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/*
72941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * Disable Probe Request reporting unless we need it in this way for
72951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * devices that include the AP SME, in the other case (unless using
72961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * monitor iface) we'll get it through the nl_mgmt socket instead.
72971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 */
72981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!drv->device_ap_sme)
72991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_driver_nl80211_probe_req_report(bss, 0);
73001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!drv->device_ap_sme && !drv->use_monitor)
73021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (nl80211_mgmt_subscribe_ap(bss))
73031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return -1;
73041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->device_ap_sme && !drv->use_monitor)
73061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
73071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			return -1;
73081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!drv->device_ap_sme && drv->use_monitor &&
73101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    nl80211_create_monitor_interface(drv) &&
73111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    !drv->device_ap_sme)
731204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return -1;
731304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
731404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#ifdef ANDROID_P2P
731504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (drv->device_ap_sme && drv->use_monitor)
7316b638fe75d3cb9d21c67386173f10afe65053cc4dDmitry Shmidt		if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
7317b638fe75d3cb9d21c67386173f10afe65053cc4dDmitry Shmidt			return -1;
7318b638fe75d3cb9d21c67386173f10afe65053cc4dDmitry Shmidt
7319b638fe75d3cb9d21c67386173f10afe65053cc4dDmitry Shmidt	if (drv->use_monitor &&
7320b638fe75d3cb9d21c67386173f10afe65053cc4dDmitry Shmidt	    nl80211_create_monitor_interface(drv))
73211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
732204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#endif
73231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->device_ap_sme &&
73251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
73261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
73271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "Probe Request frame reporting in AP mode");
73281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		/* Try to survive without this */
73291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
73301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
73321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
73331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nl80211_teardown_ap(struct i802_bss *bss)
73361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
73371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
73381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->device_ap_sme) {
73401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_driver_nl80211_probe_req_report(bss, 0);
73411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (!drv->use_monitor)
73421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			nl80211_mgmt_unsubscribe(bss, "AP teardown (dev SME)");
73431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else if (drv->use_monitor)
73441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_remove_monitor_interface(drv);
73451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	else
73461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_mgmt_unsubscribe(bss, "AP teardown");
73471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	bss->beacon_set = 0;
73491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
73501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_send_eapol_data(struct i802_bss *bss,
73531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   const u8 *addr, const u8 *data,
73541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   size_t data_len)
73551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
73561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct sockaddr_ll ll;
73571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int ret;
73581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (bss->drv->eapol_tx_sock < 0) {
73601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: No socket to send EAPOL");
73611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
73621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
73631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memset(&ll, 0, sizeof(ll));
73651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ll.sll_family = AF_PACKET;
73661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ll.sll_ifindex = bss->ifindex;
73671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ll.sll_protocol = htons(ETH_P_PAE);
73681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ll.sll_halen = ETH_ALEN;
73691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memcpy(ll.sll_addr, addr, ETH_ALEN);
73701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0,
73711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		     (struct sockaddr *) &ll, sizeof(ll));
73721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ret < 0)
73731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: EAPOL TX: %s",
73741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   strerror(errno));
73751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return ret;
73771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
73781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
73808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
73818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
73828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_hapd_send_eapol(
73838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *priv, const u8 *addr, const u8 *data,
73848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t data_len, int encrypt, const u8 *own_addr, u32 flags)
73858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
73868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
73878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
73888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee80211_hdr *hdr;
73898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len;
73908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *pos;
73918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res;
73928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int qos = flags & WPA_STA_WMM;
7393b638fe75d3cb9d21c67386173f10afe65053cc4dDmitry Shmidt#ifndef ANDROID_P2P
73941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->device_ap_sme || !drv->use_monitor)
7395b638fe75d3cb9d21c67386173f10afe65053cc4dDmitry Shmidt#else
7396b638fe75d3cb9d21c67386173f10afe65053cc4dDmitry Shmidt	if (drv->device_ap_sme && !drv->use_monitor)
7397b638fe75d3cb9d21c67386173f10afe65053cc4dDmitry Shmidt#endif
73981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return nl80211_send_eapol_data(bss, addr, data, data_len);
73991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
74008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
74018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data_len;
74028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = os_zalloc(len);
74038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hdr == NULL) {
74048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		printf("malloc() failed for i802_send_data(len=%lu)\n",
74058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       (unsigned long) len);
74068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
74078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
74088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
74098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr->frame_control =
74108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
74118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
74128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encrypt)
74138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
74148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (qos) {
74158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hdr->frame_control |=
74168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
74178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
74188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
74198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
74208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
74218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
74228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = (u8 *) (hdr + 1);
74238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
74248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (qos) {
7425aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt		/* Set highest priority in QoS header */
7426aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt		pos[0] = 7;
74278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos[1] = 0;
74288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
74298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
74308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
74318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
74328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += sizeof(rfc1042_header);
74338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE16(pos, ETH_P_PAE);
74348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += 2;
74358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(pos, data, data_len);
74368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7437c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0,
7438c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					    0, 0, 0, 0);
74398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res < 0) {
74408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
74418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "failed: %d (%s)",
74428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (unsigned long) len, errno, strerror(errno));
74438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
74448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(hdr);
74458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
74468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return res;
74478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
74488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
74498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
74508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
74518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    int total_flags,
74528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    int flags_or, int flags_and)
74538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
74548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
74558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
74568da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	struct nl_msg *msg;
74578da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	struct nlattr *flags;
74588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl80211_sta_flag_update upd;
74598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
74608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
74618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
74628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
74638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
74641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
74658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
74668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
74678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    if_nametoindex(bss->ifname));
74688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
74698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
74708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
74718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
74728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * can be removed eventually.
74738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
74748da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	flags = nla_nest_start(msg, NL80211_ATTR_STA_FLAGS);
74758da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	if (!flags)
74768da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		goto nla_put_failure;
74778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (total_flags & WPA_STA_AUTHORIZED)
74788da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_AUTHORIZED);
74798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
74808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (total_flags & WPA_STA_WMM)
74818da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_WME);
74828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
74838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (total_flags & WPA_STA_SHORT_PREAMBLE)
74848da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_SHORT_PREAMBLE);
74858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
74868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (total_flags & WPA_STA_MFP)
74878da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_MFP);
74888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
74891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (total_flags & WPA_STA_TDLS_PEER)
74908da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_TDLS_PEER);
74911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
74928da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	nla_nest_end(msg, flags);
74938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
74948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&upd, 0, sizeof(upd));
74958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
74968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	upd.set = sta_flags_nl80211(flags_or);
74978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
74988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
74998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
75008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
75011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
75028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
75038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
75048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
75058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
75068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
75078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 struct wpa_driver_associate_params *params)
75088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7509a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	enum nl80211_iftype nlmode, old_mode;
7510a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	struct hostapd_freq_params freq = {
7511a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		.freq = params->freq,
7512a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	};
75131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
75141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->p2p) {
75158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P "
75168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "group (GO)");
75171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nlmode = NL80211_IFTYPE_P2P_GO;
75181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else
75191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nlmode = NL80211_IFTYPE_AP;
75201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
7521a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	old_mode = drv->nlmode;
7522a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode)) {
7523a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		nl80211_remove_monitor_interface(drv);
7524a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return -1;
7525a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	}
7526a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
7527a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (wpa_driver_nl80211_set_freq(&drv->first_bss, &freq)) {
7528a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		if (old_mode != nlmode)
7529a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			wpa_driver_nl80211_set_mode(&drv->first_bss, old_mode);
75308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_remove_monitor_interface(drv);
75318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
75328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
75338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
75348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
75358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
75368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
75378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
75388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv)
75398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
75408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
75418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
75428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
75438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
75448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
75458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
75468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
75471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_LEAVE_IBSS);
75488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
75498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
75508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
75518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
75528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
75538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", ret, strerror(-ret));
75548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
75558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
75568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
75578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = 0;
75588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS request sent successfully");
75598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
75608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
75618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
75628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
75638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
75648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
75658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
75668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
75678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   struct wpa_driver_associate_params *params)
75688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
75698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
75708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
75718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int count = 0;
75728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
75738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
75748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
75751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (wpa_driver_nl80211_set_mode(&drv->first_bss,
75761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					NL80211_IFTYPE_ADHOC)) {
75778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
75788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "IBSS mode");
75798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
75808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
75818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
75828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtretry:
75838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
75848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
75858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
75868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
75871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_JOIN_IBSS);
75888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
75898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
75908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
75918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
75928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
75938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
75948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  params->ssid, params->ssid_len);
75958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
75968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		params->ssid);
75978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(drv->ssid, params->ssid, params->ssid_len);
75988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->ssid_len = params->ssid_len;
75998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
76008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
76018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
76028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
76038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = nl80211_set_conn_keys(params, msg);
76048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret)
76058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
76068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7607c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (params->bssid && params->fixed_bssid) {
7608c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * BSSID=" MACSTR,
7609c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			   MAC2STR(params->bssid));
7610c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
7611c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
7612c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
7613c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
7614c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	    params->key_mgmt_suite == KEY_MGMT_PSK ||
7615c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	    params->key_mgmt_suite == KEY_MGMT_802_1X_SHA256 ||
7616c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	    params->key_mgmt_suite == KEY_MGMT_PSK_SHA256) {
7617c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * control port");
7618c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
7619c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
7620c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
76218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->wpa_ie) {
76228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_DEBUG,
76238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    "  * Extra IEs for Beacon/Probe Response frames",
76248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    params->wpa_ie, params->wpa_ie_len);
76258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
76268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->wpa_ie);
76278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
76288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
76298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
76308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
76318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
76328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
76338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ret, strerror(-ret));
76348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		count++;
76358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret == -EALREADY && count == 1) {
76368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
76378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "forced leave");
76388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nl80211_leave_ibss(drv);
76398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nlmsg_free(msg);
76408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto retry;
76418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
76428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
76438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
76448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
76458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = 0;
76468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Join IBSS request sent successfully");
76478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
76488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
76498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
76508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
76518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
76528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
76538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7654d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtstatic int wpa_driver_nl80211_try_connect(
76558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv,
76568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_associate_params *params)
76578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
76588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
76598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum nl80211_auth_type type;
76608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = 0;
76618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int algs;
76628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
76638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
76648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
76658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
76668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
76678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
76681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_CONNECT);
76698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
76708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
76718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->bssid) {
76728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * bssid=" MACSTR,
76738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(params->bssid));
76748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
76758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
76768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->freq) {
76778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
76788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
7679b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		drv->assoc_freq = params->freq;
7680b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	} else
7681b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		drv->assoc_freq = 0;
768204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (params->bg_scan_period >= 0) {
768304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * bg scan period=%d",
768404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			   params->bg_scan_period);
768504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		NLA_PUT_U16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
768604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			    params->bg_scan_period);
768704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
76888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->ssid) {
76898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
76908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  params->ssid, params->ssid_len);
76918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
76928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->ssid);
76938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->ssid_len > sizeof(drv->ssid))
76948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto nla_put_failure;
76958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(drv->ssid, params->ssid, params->ssid_len);
76968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->ssid_len = params->ssid_len;
76978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
76988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "  * IEs", params->wpa_ie, params->wpa_ie_len);
76998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->wpa_ie)
77008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
77018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->wpa_ie);
77028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
77038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	algs = 0;
77048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->auth_alg & WPA_AUTH_ALG_OPEN)
77058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		algs++;
77068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->auth_alg & WPA_AUTH_ALG_SHARED)
77078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		algs++;
77088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->auth_alg & WPA_AUTH_ALG_LEAP)
77098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		algs++;
77108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (algs > 1) {
77118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * Leave out Auth Type for automatic "
77128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "selection");
77138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto skip_auth_type;
77148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
77158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
77168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->auth_alg & WPA_AUTH_ALG_OPEN)
77178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		type = NL80211_AUTHTYPE_OPEN_SYSTEM;
77188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
77198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		type = NL80211_AUTHTYPE_SHARED_KEY;
77208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
77218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		type = NL80211_AUTHTYPE_NETWORK_EAP;
77228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (params->auth_alg & WPA_AUTH_ALG_FT)
77238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		type = NL80211_AUTHTYPE_FT;
77248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
77258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
77268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
77278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "  * Auth Type %d", type);
77288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
77298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
77308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtskip_auth_type:
77311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (params->wpa_proto) {
77321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		enum nl80211_wpa_versions ver = 0;
77338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
77341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (params->wpa_proto & WPA_PROTO_WPA)
77351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			ver |= NL80211_WPA_VERSION_1;
77361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (params->wpa_proto & WPA_PROTO_RSN)
77371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			ver |= NL80211_WPA_VERSION_2;
77388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
77391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * WPA Versions 0x%x", ver);
77408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
77418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
77428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
77438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->pairwise_suite != CIPHER_NONE) {
77448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int cipher;
77458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
77468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (params->pairwise_suite) {
7747d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		case CIPHER_SMS4:
7748d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			cipher = WLAN_CIPHER_SUITE_SMS4;
7749d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			break;
77508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_WEP40:
77518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_WEP40;
77528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
77538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_WEP104:
77548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_WEP104;
77558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
77568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_CCMP:
77578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_CCMP;
77588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
775961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		case CIPHER_GCMP:
776061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_GCMP;
776161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			break;
77628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_TKIP:
77638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
77648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_TKIP;
77658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
77668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
77678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
77688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
77698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
77708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->group_suite != CIPHER_NONE) {
77718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int cipher;
77728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
77738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (params->group_suite) {
7774d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		case CIPHER_SMS4:
7775d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			cipher = WLAN_CIPHER_SUITE_SMS4;
7776d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			break;
77778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_WEP40:
77788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_WEP40;
77798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
77808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_WEP104:
77818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_WEP104;
77828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
77838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_CCMP:
77848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_CCMP;
77858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
778661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		case CIPHER_GCMP:
778761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_GCMP;
778861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			break;
77898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_TKIP:
77908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
77918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_TKIP;
77928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
77938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
77948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
77958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
77968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
77978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
7798d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	    params->key_mgmt_suite == KEY_MGMT_PSK ||
7799700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	    params->key_mgmt_suite == KEY_MGMT_FT_802_1X ||
7800700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	    params->key_mgmt_suite == KEY_MGMT_FT_PSK ||
7801d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	    params->key_mgmt_suite == KEY_MGMT_CCKM) {
78028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int mgmt = WLAN_AKM_SUITE_PSK;
78038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
78048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (params->key_mgmt_suite) {
7805d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		case KEY_MGMT_CCKM:
7806d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			mgmt = WLAN_AKM_SUITE_CCKM;
7807d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			break;
78088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case KEY_MGMT_802_1X:
78098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			mgmt = WLAN_AKM_SUITE_8021X;
78108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
7811700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt		case KEY_MGMT_FT_802_1X:
7812700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt			mgmt = WLAN_AKM_SUITE_FT_8021X;
7813700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt			break;
7814700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt		case KEY_MGMT_FT_PSK:
7815700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt			mgmt = WLAN_AKM_SUITE_FT_PSK;
7816700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt			break;
78178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case KEY_MGMT_PSK:
78188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
78198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			mgmt = WLAN_AKM_SUITE_PSK;
78208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
78218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
78228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
78238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
78248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7825a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#ifdef CONFIG_IEEE80211W
7826a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
7827a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
7828a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
7829a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
7830c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (params->disable_ht)
7831c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
7832c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
7833c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (params->htcaps && params->htcaps_mask) {
7834c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		int sz = sizeof(struct ieee80211_ht_capabilities);
7835c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps);
7836c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
7837c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			params->htcaps_mask);
7838c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
7839c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
78402f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt#ifdef CONFIG_VHT_OVERRIDES
78412f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (params->disable_vht) {
78422f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * VHT disabled");
78432f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT);
78442f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
78452f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
78462f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (params->vhtcaps && params->vhtcaps_mask) {
78472f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		int sz = sizeof(struct ieee80211_vht_capabilities);
78482f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps);
78492f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
78502f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			params->vhtcaps_mask);
78512f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
78522f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt#endif /* CONFIG_VHT_OVERRIDES */
78532f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
78548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = nl80211_set_conn_keys(params, msg);
78558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret)
78568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
78578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
78588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
78598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
78608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
78618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
78628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", ret, strerror(-ret));
78638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
78648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
78658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = 0;
78668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Connect request send successfully");
78678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
78688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
78698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
78708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
78718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
78728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
78738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
78748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7875d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidtstatic int wpa_driver_nl80211_connect(
7876d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	struct wpa_driver_nl80211_data *drv,
7877d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	struct wpa_driver_associate_params *params)
7878d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt{
7879d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	int ret = wpa_driver_nl80211_try_connect(drv, params);
7880d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	if (ret == -EALREADY) {
7881d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		/*
7882d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		 * cfg80211 does not currently accept new connections if
7883d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		 * we are already connected. As a workaround, force
7884d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		 * disconnection and try again.
7885d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		 */
7886d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Explicitly "
7887d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			   "disconnecting before reassociation "
7888d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			   "attempt");
7889d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		if (wpa_driver_nl80211_disconnect(
7890d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			    drv, WLAN_REASON_PREV_AUTH_NOT_VALID))
7891d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt			return -1;
7892d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		ret = wpa_driver_nl80211_try_connect(drv, params);
7893d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	}
7894d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	return ret;
7895d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt}
7896d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
7897d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt
78988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_associate(
78998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *priv, struct wpa_driver_associate_params *params)
79008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
79018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
79028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
79038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
79048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
79058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
79068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->mode == IEEE80211_MODE_AP)
79078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return wpa_driver_nl80211_ap(drv, params);
79088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
79098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->mode == IEEE80211_MODE_IBSS)
79108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return wpa_driver_nl80211_ibss(drv, params);
79118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
79128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
79131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		enum nl80211_iftype nlmode = params->p2p ?
79141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
79151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
79161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
79178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
79188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return wpa_driver_nl80211_connect(drv, params);
79198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
79208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
79218bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	nl80211_mark_disconnected(drv);
79228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
79238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
79248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
79258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
79268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
79278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
79288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   drv->ifindex);
79291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE);
79308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
79318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
79328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->bssid) {
79338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * bssid=" MACSTR,
79348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(params->bssid));
79358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
79368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
79378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->freq) {
79388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
79398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
79408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->assoc_freq = params->freq;
79418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else
79428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->assoc_freq = 0;
794304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (params->bg_scan_period >= 0) {
794404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * bg scan period=%d",
794504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			   params->bg_scan_period);
794604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		NLA_PUT_U16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
794704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt			    params->bg_scan_period);
794804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	}
79498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->ssid) {
79508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
79518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  params->ssid, params->ssid_len);
79528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
79538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->ssid);
79548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->ssid_len > sizeof(drv->ssid))
79558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto nla_put_failure;
79568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(drv->ssid, params->ssid, params->ssid_len);
79578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->ssid_len = params->ssid_len;
79588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
79598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "  * IEs", params->wpa_ie, params->wpa_ie_len);
79608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->wpa_ie)
79618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
79628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->wpa_ie);
79638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
79648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->pairwise_suite != CIPHER_NONE) {
79658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int cipher;
79668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
79678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (params->pairwise_suite) {
79688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_WEP40:
79698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_WEP40;
79708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
79718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_WEP104:
79728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_WEP104;
79738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
79748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_CCMP:
79758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_CCMP;
79768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
797761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		case CIPHER_GCMP:
797861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_GCMP;
797961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			break;
79808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_TKIP:
79818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
79828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_TKIP;
79838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
79848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
79858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * pairwise=0x%x", cipher);
79868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
79878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
79888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
79898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->group_suite != CIPHER_NONE) {
79908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int cipher;
79918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
79928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (params->group_suite) {
79938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_WEP40:
79948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_WEP40;
79958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
79968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_WEP104:
79978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_WEP104;
79988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
79998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_CCMP:
80008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_CCMP;
80018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
800261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		case CIPHER_GCMP:
800361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_GCMP;
800461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			break;
80058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_TKIP:
80068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
80078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_TKIP;
80088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
80098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
80108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * group=0x%x", cipher);
80118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
80128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
80138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
80148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211W
80158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
80168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
80178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
80188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
80198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
80208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
80218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->prev_bssid) {
80228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * prev_bssid=" MACSTR,
80238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(params->prev_bssid));
80248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
80258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->prev_bssid);
80268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
80278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8028c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (params->disable_ht)
8029c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
8030c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
8031c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (params->htcaps && params->htcaps_mask) {
8032c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		int sz = sizeof(struct ieee80211_ht_capabilities);
8033c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps);
8034c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
8035c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			params->htcaps_mask);
8036c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	}
8037c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
80382f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt#ifdef CONFIG_VHT_OVERRIDES
80392f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (params->disable_vht) {
80402f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		wpa_printf(MSG_DEBUG, "  * VHT disabled");
80412f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT);
80422f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
80432f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
80442f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	if (params->vhtcaps && params->vhtcaps_mask) {
80452f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		int sz = sizeof(struct ieee80211_vht_capabilities);
80462f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps);
80472f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
80482f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt			params->vhtcaps_mask);
80492f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt	}
80502f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt#endif /* CONFIG_VHT_OVERRIDES */
80512f023193a0fd630eb82ce6381b80911ad5a3462fDmitry Shmidt
80528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->p2p)
80538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * P2P group");
80548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
80558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
80568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
80578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
80581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_dbg(drv->ctx, MSG_DEBUG,
80591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			"nl80211: MLME command failed (assoc): ret=%d (%s)",
80601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			ret, strerror(-ret));
80618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_dump_scan(drv);
80628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
80638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
80648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = 0;
80658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Association request send "
80668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "successfully");
80678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
80688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
80698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
80708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
80718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
80728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
80738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
80748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
80751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    int ifindex, enum nl80211_iftype mode)
80768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
80778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
80788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -ENOBUFS;
80798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
80801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Set mode ifindex %d iftype %d (%s)",
80811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   ifindex, mode, nl80211_iftype_str(mode));
80821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
80838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
80848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
80858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
80868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
80871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
808834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (nl80211_set_iface_id(msg, &drv->first_bss) < 0)
808934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		goto nla_put_failure;
80908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
80918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
80928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
80931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
80948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!ret)
80958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
80968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
80971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
80988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
80998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   " %d (%s)", ifindex, mode, ret, strerror(-ret));
81008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
81018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
81028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
81038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
81041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
81051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				       enum nl80211_iftype nlmode)
81068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
81078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
81088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
81098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
81101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int was_ap = is_ap_interface(drv->nlmode);
81111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int res;
81128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
81131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	res = nl80211_set_mode(drv, drv->ifindex, nlmode);
811434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (res && nlmode == nl80211_get_ifmode(bss))
811534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		res = 0;
811634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
81171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (res == 0) {
81188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->nlmode = nlmode;
81198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = 0;
81208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto done;
81218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
81228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
81231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (res == -ENODEV)
81241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1;
81251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
81268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nlmode == drv->nlmode) {
81278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
81288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "requested mode - ignore error");
81298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = 0;
81308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto done; /* Already in the requested mode */
81318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
81328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
81338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* mac80211 doesn't allow mode changes while the device is up, so
81348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * take the device down, try to set the mode again, and bring the
81358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * device back up.
81368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
81378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
81388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "interface down");
81398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < 10; i++) {
814034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		res = i802_set_iface_flags(bss, 0);
81411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (res == -EACCES || res == -ENODEV)
81421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
81431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (res == 0) {
81448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* Try to set the mode again while the interface is
81458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * down */
81468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
81471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (ret == -EACCES)
81481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				break;
814934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			res = i802_set_iface_flags(bss, 1);
81501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (res && !ret)
81518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				ret = -1;
81521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			else if (ret != -EBUSY)
81538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
81548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else
81558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Failed to set "
81568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "interface down");
81578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_sleep(0, 100000);
81588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
81598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
81608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!ret) {
81618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
81628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "interface is down");
81638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->nlmode = nlmode;
81641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		drv->ignore_if_down_event = 1;
81658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
81668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
81678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtdone:
81681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ret) {
81691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
81701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "from %d failed", nlmode, drv->nlmode);
81711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return ret;
81721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
81731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
817434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (is_p2p_net_interface(nlmode))
817561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		nl80211_disable_11b_rates(drv, drv->ifindex, 1);
817661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	else if (drv->disabled_11b_rates)
817761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		nl80211_disable_11b_rates(drv, drv->ifindex, 0);
817861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
81791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (is_ap_interface(nlmode)) {
81801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_mgmt_unsubscribe(bss, "start AP");
81818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Setup additional AP mode functionality if needed */
81821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (nl80211_setup_ap(bss))
81838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
81841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else if (was_ap) {
81858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Remove additional AP mode functionality */
81861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_teardown_ap(bss);
81871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else {
81881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_mgmt_unsubscribe(bss, "mode change");
81898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
81908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
819104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (!bss->in_deinit && !is_ap_interface(nlmode) &&
81921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	    nl80211_mgmt_subscribe_non_ap(bss) < 0)
81931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
81941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "frame processing - ignore for now");
81958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
81961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
81978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
81988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
81998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
82008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_get_capa(void *priv,
82018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       struct wpa_driver_capa *capa)
82028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
82038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
82048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
82058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!drv->has_capability)
82068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
82078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(capa, &drv->capa, sizeof(*capa));
8208444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	if (drv->extended_capa && drv->extended_capa_mask) {
8209444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		capa->extended_capa = drv->extended_capa;
8210444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		capa->extended_capa_mask = drv->extended_capa_mask;
8211444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		capa->extended_capa_len = drv->extended_capa_len;
8212444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	}
821334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
821434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if ((capa->flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE) &&
821534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	    !drv->allow_p2p_device) {
821634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Do not indicate P2P_DEVICE support (p2p_device=1 driver param not specified)");
821734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		capa->flags &= ~WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE;
821834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
821934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
82208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
82218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
82228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
82238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
82248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_set_operstate(void *priv, int state)
82258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
82268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
82278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
82288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
82298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
82308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   __func__, drv->operstate, state, state ? "UP" : "DORMANT");
82318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->operstate = state;
82321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1,
82338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      state ? IF_OPER_UP : IF_OPER_DORMANT);
82348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
82358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
82368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
82378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
82388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
82398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
82408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
82418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
82428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl80211_sta_flag_update upd;
82438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
82448bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for "
82458bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt		   MACSTR, authorized ? "" : "un", MAC2STR(drv->bssid));
82468bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt
82478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
82488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
82498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
82508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
82511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
82528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
82538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
82548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    if_nametoindex(bss->ifname));
82558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
82568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
82578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&upd, 0, sizeof(upd));
82588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED);
82598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (authorized)
82608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
82618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
82628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
82638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
82648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
82651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
82668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
82678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
82688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
82698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
827075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen/* Set kernel driver on given frequency (MHz) */
827175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
82728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
827375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct i802_bss *bss = priv;
8274a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	return wpa_driver_nl80211_set_freq(bss, freq);
82758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
82768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
82778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
827875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen#if defined(HOSTAPD) || defined(CONFIG_AP)
82798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
82808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic inline int min_int(int a, int b)
82818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
82828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (a < b)
82838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return a;
82848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return b;
82858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
82868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
82878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
82888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int get_key_handler(struct nl_msg *msg, void *arg)
82898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
82908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
82918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
82928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
82938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
82948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
82958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
82968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
82978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * TODO: validate the key index and mac address!
82988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Otherwise, there's a race condition as soon as
82998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * the kernel starts sending key notifications.
83008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
83018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
83028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_KEY_SEQ])
83038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]),
83048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6));
83058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
83068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
83078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
83088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
83098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
83108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   int idx, u8 *seq)
83118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
83128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
83138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
83148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
83158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
83168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
83178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
83188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
83198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
83201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_KEY);
83218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
83228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (addr)
83238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
83248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);
83258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
83268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
83278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memset(seq, 0, 6);
83288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
83298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, get_key_handler, seq);
83308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
83311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
83328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
83338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
83348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
83358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
83368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_set_rts(void *priv, int rts)
83378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
83388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
83398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
83408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
83418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -ENOBUFS;
83428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 val;
83438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
83448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
83458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
83468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
83478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
83488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (rts >= 2347)
83498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val = (u32) -1;
83508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
83518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val = rts;
83528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
83531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
83548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
83558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val);
83568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
83578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
83581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
83598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!ret)
83608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
83618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
83621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
83638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
83648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "%d (%s)", rts, ret, strerror(-ret));
83658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
83668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
83678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
83688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
83698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_set_frag(void *priv, int frag)
83708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
83718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
83728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
83738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
83748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -ENOBUFS;
83758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 val;
83768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
83778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
83788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
83798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
83808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
83818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (frag >= 2346)
83828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val = (u32) -1;
83838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
83848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val = frag;
83858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
83861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
83878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
83888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val);
83898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
83908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
83911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
83928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!ret)
83938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
83948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
83951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
83968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
83978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "%d: %d (%s)", frag, ret, strerror(-ret));
83988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
83998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
84008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
84018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
84028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_flush(void *priv)
84038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
84048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
84058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
84068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
84071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int res;
84088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
84098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
84108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
84118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
84128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8413b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: flush -> DEL_STATION %s (all)",
8414b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		   bss->ifname);
84151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
84168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
84178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
84188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * XXX: FIX! this needs to flush all VLANs too
84198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
84208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
84218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    if_nametoindex(bss->ifname));
84228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
84231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	res = send_and_recv_msgs(drv, msg, NULL, NULL);
84241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (res) {
84251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
84261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "(%s)", res, strerror(-res));
84271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
84281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return res;
84291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt nla_put_failure:
84301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
84318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
84328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
84338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
84341e6c57fee4a56b421cc20f6dc0785c9138b21337Jouni Malinen#endif /* HOSTAPD || CONFIG_AP */
84351e6c57fee4a56b421cc20f6dc0785c9138b21337Jouni Malinen
84368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
84378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int get_sta_handler(struct nl_msg *msg, void *arg)
84388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
84398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
84408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
84418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostap_sta_driver_data *data = arg;
84428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *stats[NL80211_STA_INFO_MAX + 1];
84438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
84448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
84458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
84468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
84478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
84488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
84491e6c57fee4a56b421cc20f6dc0785c9138b21337Jouni Malinen		[NL80211_STA_INFO_TX_FAILED] = { .type = NLA_U32 },
84508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
84518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
84528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
84538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
84548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
84558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
84568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * TODO: validate the interface and mac address!
84578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Otherwise, there's a race condition as soon as
84588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * the kernel starts sending station notifications.
84598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
84608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
84618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!tb[NL80211_ATTR_STA_INFO]) {
84628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "sta stats missing!");
84638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
84648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
84658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nla_parse_nested(stats, NL80211_STA_INFO_MAX,
84668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     tb[NL80211_ATTR_STA_INFO],
84678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     stats_policy)) {
84688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "failed to parse nested attributes!");
84698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
84708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
84718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
84728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (stats[NL80211_STA_INFO_INACTIVE_TIME])
84738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->inactive_msec =
84748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]);
84758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (stats[NL80211_STA_INFO_RX_BYTES])
84768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]);
84778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (stats[NL80211_STA_INFO_TX_BYTES])
84788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]);
84798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (stats[NL80211_STA_INFO_RX_PACKETS])
84808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->rx_packets =
84818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]);
84828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (stats[NL80211_STA_INFO_TX_PACKETS])
84838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->tx_packets =
84848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
84851e6c57fee4a56b421cc20f6dc0785c9138b21337Jouni Malinen	if (stats[NL80211_STA_INFO_TX_FAILED])
84861e6c57fee4a56b421cc20f6dc0785c9138b21337Jouni Malinen		data->tx_retry_failed =
84871e6c57fee4a56b421cc20f6dc0785c9138b21337Jouni Malinen			nla_get_u32(stats[NL80211_STA_INFO_TX_FAILED]);
84888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
84898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
84908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
84918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
84924b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int i802_read_sta_data(struct i802_bss *bss,
84934b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt			      struct hostap_sta_driver_data *data,
84948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      const u8 *addr)
84958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
84968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
84978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
84988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
84998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(data, 0, sizeof(*data));
85008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
85018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
85028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
85038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
85041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
85058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
85068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
85078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
85088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
85098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, get_sta_handler, data);
85108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
85111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
85128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
85138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
85148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
85158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
85161e6c57fee4a56b421cc20f6dc0785c9138b21337Jouni Malinen#if defined(HOSTAPD) || defined(CONFIG_AP)
85171e6c57fee4a56b421cc20f6dc0785c9138b21337Jouni Malinen
85188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_set_tx_queue_params(void *priv, int queue, int aifs,
85198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    int cw_min, int cw_max, int burst_time)
85208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
85218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
85228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
85238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
85248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *txq, *params;
85258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
85268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
85278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
85288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
85298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
85301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
85318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
85328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
85338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
85348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
85358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!txq)
85368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
85378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
85388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* We are only sending parameters for a single TXQ at a time */
85398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	params = nla_nest_start(msg, 1);
85408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!params)
85418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
85428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
85438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (queue) {
85448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case 0:
85458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO);
85468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
85478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case 1:
85488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI);
85498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
85508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case 2:
85518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE);
85528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
85538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case 3:
85548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK);
85558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
85568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
85578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Burst time is configured in units of 0.1 msec and TXOP parameter in
85588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * 32 usec, so need to convert the value here. */
85598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U16(msg, NL80211_TXQ_ATTR_TXOP, (burst_time * 100 + 16) / 32);
85608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min);
85618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max);
85628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U8(msg, NL80211_TXQ_ATTR_AIFS, aifs);
85638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
85648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_nest_end(msg, params);
85658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
85668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_nest_end(msg, txq);
85678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
85688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
85698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
85701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
85718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
85721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
85738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
85748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
85758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
85768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
85774b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int i802_set_sta_vlan(struct i802_bss *bss, const u8 *addr,
85788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     const char *ifname, int vlan_id)
85798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
85808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
85818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
85828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -ENOBUFS;
85838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
85848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
85858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
85868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
85878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
85881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
85898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
85908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
85918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    if_nametoindex(bss->ifname));
85928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
85938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN,
85948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    if_nametoindex(ifname));
85958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
85968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
85971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
85988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
85998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
86008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
86018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(addr), ifname, vlan_id, ret,
86028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   strerror(-ret));
86038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
86048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
86051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
86068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
86078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
86088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
86098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
86108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_get_inact_sec(void *priv, const u8 *addr)
86118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
86128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostap_sta_driver_data data;
86138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
86148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
86158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.inactive_msec = (unsigned long) -1;
86168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = i802_read_sta_data(priv, &data, addr);
86178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret || data.inactive_msec == (unsigned long) -1)
86188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
86198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return data.inactive_msec / 1000;
86208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
86218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
86228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
86238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_sta_clear_stats(void *priv, const u8 *addr)
86248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
86258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if 0
86268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO */
86278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
86288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
86298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
86308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
86318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
86328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
86338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   int reason)
86348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
86358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
863604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
86378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee80211_mgmt mgmt;
86388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
863904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (drv->device_ap_sme)
864004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return wpa_driver_nl80211_sta_remove(bss, addr);
864104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
86428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memset(&mgmt, 0, sizeof(mgmt));
86438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
86448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  WLAN_FC_STYPE_DEAUTH);
86458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(mgmt.da, addr, ETH_ALEN);
86468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(mgmt.sa, own_addr, ETH_ALEN);
86478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
86488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt.u.deauth.reason_code = host_to_le16(reason);
86498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
86508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    IEEE80211_HDRLEN +
86514b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					    sizeof(mgmt.u.deauth), 0, 0, 0, 0,
86524b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					    0);
86538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
86548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
86558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
86568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
86578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     int reason)
86588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
86598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
866004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
86618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee80211_mgmt mgmt;
86628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
866304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (drv->device_ap_sme)
866404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return wpa_driver_nl80211_sta_remove(bss, addr);
866504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
86668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memset(&mgmt, 0, sizeof(mgmt));
86678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
86688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  WLAN_FC_STYPE_DISASSOC);
86698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(mgmt.da, addr, ETH_ALEN);
86708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(mgmt.sa, own_addr, ETH_ALEN);
86718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
86728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt.u.disassoc.reason_code = host_to_le16(reason);
86738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
86748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    IEEE80211_HDRLEN +
86754b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					    sizeof(mgmt.u.disassoc), 0, 0, 0, 0,
86764b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					    0);
86778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
86788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
86798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD || CONFIG_AP */
86808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
86818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
86828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
868375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
868475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
868575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	int i;
868675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	int *old;
868775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
868875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d",
868975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		   ifidx);
869075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	for (i = 0; i < drv->num_if_indices; i++) {
869175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		if (drv->if_indices[i] == 0) {
869275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			drv->if_indices[i] = ifidx;
869375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			return;
869475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		}
869575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	}
869675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
869775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (drv->if_indices != drv->default_if_indices)
869875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		old = drv->if_indices;
869975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	else
870075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		old = NULL;
870175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
870261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	drv->if_indices = os_realloc_array(old, drv->num_if_indices + 1,
870361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt					   sizeof(int));
870475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (!drv->if_indices) {
870575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		if (!old)
870675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			drv->if_indices = drv->default_if_indices;
870775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		else
870875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			drv->if_indices = old;
870975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
871075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			   "interfaces");
871175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
871275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		return;
871375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	} else if (!old)
871475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		os_memcpy(drv->if_indices, drv->default_if_indices,
871575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			  sizeof(drv->default_if_indices));
871675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	drv->if_indices[drv->num_if_indices] = ifidx;
871775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	drv->num_if_indices++;
871875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
871975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
872075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
872175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
872275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
872375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	int i;
872475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
872575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	for (i = 0; i < drv->num_if_indices; i++) {
872675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		if (drv->if_indices[i] == ifidx) {
872775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			drv->if_indices[i] = 0;
872875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			break;
872975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		}
873075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	}
873175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
873275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
873375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
873475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
873575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
873675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	int i;
873775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
873875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	for (i = 0; i < drv->num_if_indices; i++)
873975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		if (drv->if_indices[i] == ifidx)
874075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			return 1;
874175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
874275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	return 0;
874375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
874475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
874575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
874675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
8747c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt                            const char *bridge_ifname, char *ifname_wds)
874875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
874975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct i802_bss *bss = priv;
875075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct wpa_driver_nl80211_data *drv = bss->drv;
875175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	char name[IFNAMSIZ + 1];
875275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
875375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
8754c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	if (ifname_wds)
8755c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		os_strlcpy(ifname_wds, name, IFNAMSIZ + 1);
8756c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt
875775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
875875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		   " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
875975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (val) {
876075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		if (!if_nametoindex(name)) {
876175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			if (nl80211_create_iface(drv, name,
876275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen						 NL80211_IFTYPE_AP_VLAN,
876334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt						 bss->addr, 1, NULL, NULL) < 0)
876475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen				return -1;
876575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			if (bridge_ifname &&
87661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			    linux_br_add_if(drv->global->ioctl_sock,
87671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					    bridge_ifname, name) < 0)
876875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen				return -1;
876975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		}
877061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (linux_set_iface_flags(drv->global->ioctl_sock, name, 1)) {
877161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			wpa_printf(MSG_ERROR, "nl80211: Failed to set WDS STA "
877261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt				   "interface %s up", name);
877361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		}
877475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		return i802_set_sta_vlan(priv, addr, name, 0);
877575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	} else {
8776aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt		if (bridge_ifname)
8777aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt			linux_br_del_if(drv->global->ioctl_sock, bridge_ifname,
8778aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt					name);
8779aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt
878075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		i802_set_sta_vlan(priv, addr, bss->ifname, 0);
878175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
878275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen						    name);
878375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	}
878475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
878575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
878675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
878775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
878875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
878975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct wpa_driver_nl80211_data *drv = eloop_ctx;
879075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct sockaddr_ll lladdr;
879175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	unsigned char buf[3000];
879275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	int len;
879375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	socklen_t fromlen = sizeof(lladdr);
879475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
879575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	len = recvfrom(sock, buf, sizeof(buf), 0,
879675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		       (struct sockaddr *)&lladdr, &fromlen);
879775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (len < 0) {
879875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		perror("recv");
879975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		return;
880075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	}
880175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
880275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (have_ifidx(drv, lladdr.sll_ifindex))
880375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
880475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
880575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
880675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
88078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
88088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     struct i802_bss *bss,
88098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     const char *brname, const char *ifname)
88108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
88118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifindex;
88128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char in_br[IFNAMSIZ];
88138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
88148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_strlcpy(bss->brname, brname, IFNAMSIZ);
88158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ifindex = if_nametoindex(brname);
88168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ifindex == 0) {
88178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
88188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Bridge was configured, but the bridge device does
88198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * not exist. Try to add it now.
88208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
88211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (linux_br_add(drv->global->ioctl_sock, brname) < 0) {
88228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
88238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "bridge interface %s: %s",
88248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   brname, strerror(errno));
88258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
88268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
88278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->added_bridge = 1;
88288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		add_ifidx(drv, if_nametoindex(brname));
88298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
88308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
88318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (linux_br_get(in_br, ifname) == 0) {
88328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strcmp(in_br, brname) == 0)
88338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 0; /* already in the bridge */
88348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
88358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
88368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "bridge %s", ifname, in_br);
88371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) <
88381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    0) {
88398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "nl80211: Failed to "
88408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "remove interface %s from bridge "
88418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "%s: %s",
88428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   ifname, brname, strerror(errno));
88438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
88448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
88458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
88468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
88478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
88488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   ifname, brname);
88491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) {
88508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to add interface %s "
88518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "into bridge %s: %s",
88528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ifname, brname, strerror(errno));
88538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
88548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
88558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss->added_if_into_bridge = 1;
88568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
88578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
88588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
88598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
88608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
88618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void *i802_init(struct hostapd_data *hapd,
88628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       struct wpa_init_params *params)
88638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
88648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv;
88658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss;
88668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
88678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char brname[IFNAMSIZ];
88688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifindex, br_ifindex;
88698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int br_added = 0;
88708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
88711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	bss = wpa_driver_nl80211_init(hapd, params->ifname,
88721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				      params->global_priv);
88738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss == NULL)
88748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
88758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
88768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv = bss->drv;
88778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->nlmode = NL80211_IFTYPE_AP;
88781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv->eapol_sock = -1;
88791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
88808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (linux_br_get(brname, params->ifname) == 0) {
88818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
88828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   params->ifname, brname);
88838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		br_ifindex = if_nametoindex(brname);
88848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
88858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		brname[0] = '\0';
88868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		br_ifindex = 0;
88878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
88888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
88898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
88908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->if_indices = drv->default_if_indices;
88918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < params->num_bridge; i++) {
88928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->bridge[i]) {
88938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ifindex = if_nametoindex(params->bridge[i]);
88948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ifindex)
88958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				add_ifidx(drv, ifindex);
88968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ifindex == br_ifindex)
88978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				br_added = 1;
88988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
88998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
89008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!br_added && br_ifindex &&
89018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (params->num_bridge == 0 || !params->bridge[0]))
89028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		add_ifidx(drv, br_ifindex);
89038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
89048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* start listening for EAPOL on the default AP interface */
89058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	add_ifidx(drv, drv->ifindex);
89068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
89071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0))
89088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
89098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
89108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->bssid) {
89111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
89128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       params->bssid))
89138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto failed;
89148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
89158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
89161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (wpa_driver_nl80211_set_mode(bss, drv->nlmode)) {
89178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
89188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "into AP mode", bss->ifname);
89198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
89208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
89218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
89228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->num_bridge && params->bridge[0] &&
89238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
89248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
89258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
89261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1))
89278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
89288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
89298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
89308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->eapol_sock < 0) {
89318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)");
89328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
89338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
89348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
89358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
89368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
89378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		printf("Could not register read socket for eapol\n");
89388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
89398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
89408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
89411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
89421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			       params->own_addr))
89438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
89448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
89451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	memcpy(bss->addr, params->own_addr, ETH_ALEN);
89461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
89478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return bss;
89488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
89498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfailed:
89501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_driver_nl80211_deinit(bss);
89518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
89528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
89538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
89548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
89558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void i802_deinit(void *priv)
89568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
89574b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct i802_bss *bss = priv;
89584b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	wpa_driver_nl80211_deinit(bss);
89598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
89608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
89618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
89628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
89638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
89648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic enum nl80211_iftype wpa_driver_nl80211_if_type(
89658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum wpa_driver_if_type type)
89668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
89678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (type) {
89688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_IF_STATION:
89698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL80211_IFTYPE_STATION;
89708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_IF_P2P_CLIENT:
89718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_IF_P2P_GROUP:
89728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL80211_IFTYPE_P2P_CLIENT;
89738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_IF_AP_VLAN:
89748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL80211_IFTYPE_AP_VLAN;
89758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_IF_AP_BSS:
89768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL80211_IFTYPE_AP;
89778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_IF_P2P_GO:
89788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL80211_IFTYPE_P2P_GO;
897934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case WPA_IF_P2P_DEVICE:
898034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NL80211_IFTYPE_P2P_DEVICE;
89818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
89828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
89838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
89848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
89858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
89868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
89878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
89888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
89898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
89908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv;
89918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each(drv, &global->interfaces,
89928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 struct wpa_driver_nl80211_data, list) {
89931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (os_memcmp(addr, drv->first_bss.addr, ETH_ALEN) == 0)
89948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 1;
89958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
89968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
89978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
89988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
89998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
90008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
90018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      u8 *new_addr)
90028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
90038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int idx;
90048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
90058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!drv->global)
90068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
90078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
90081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memcpy(new_addr, drv->first_bss.addr, ETH_ALEN);
90098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (idx = 0; idx < 64; idx++) {
90101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		new_addr[0] = drv->first_bss.addr[0] | 0x02;
90118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		new_addr[0] ^= idx << 2;
90128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!nl80211_addr_in_use(drv->global, new_addr))
90138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
90148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
90158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (idx == 64)
90168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
90178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
90188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Assigned new P2P Interface Address "
90198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   MACSTR, MAC2STR(new_addr));
90208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
90218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
90228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
90238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
90248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
90258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
90268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
902734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstruct wdev_info {
902834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u64 wdev_id;
902934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	int wdev_id_set;
903034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	u8 macaddr[ETH_ALEN];
903134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt};
903234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
903334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int nl80211_wdev_handler(struct nl_msg *msg, void *arg)
903434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
903534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
903634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
903734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wdev_info *wi = arg;
903834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
903934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
904034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
904134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (tb[NL80211_ATTR_WDEV]) {
904234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wi->wdev_id = nla_get_u64(tb[NL80211_ATTR_WDEV]);
904334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wi->wdev_id_set = 1;
904434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
904534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
904634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (tb[NL80211_ATTR_MAC])
904734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		os_memcpy(wi->macaddr, nla_data(tb[NL80211_ATTR_MAC]),
904834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			  ETH_ALEN);
904934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
905034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return NL_SKIP;
905134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
905234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
905334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
90548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
90558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     const char *ifname, const u8 *addr,
90568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     void *bss_ctx, void **drv_priv,
90578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     char *force_ifname, u8 *if_addr,
90588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     const char *bridge)
90598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
906034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	enum nl80211_iftype nlmode;
90618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
90628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
90638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifidx;
90648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
90658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *new_bss = NULL;
90668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
90678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (type == WPA_IF_AP_BSS) {
90688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		new_bss = os_zalloc(sizeof(*new_bss));
90698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (new_bss == NULL)
90708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
90718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
90728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
90738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
90748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (addr)
90758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(if_addr, addr, ETH_ALEN);
907634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	nlmode = wpa_driver_nl80211_if_type(type);
907734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (nlmode == NL80211_IFTYPE_P2P_DEVICE) {
907834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		struct wdev_info p2pdev_info;
907934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
908034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		os_memset(&p2pdev_info, 0, sizeof(p2pdev_info));
908134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
908234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					     0, nl80211_wdev_handler,
908334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					     &p2pdev_info);
908434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (!p2pdev_info.wdev_id_set || ifidx != 0) {
908534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			wpa_printf(MSG_ERROR, "nl80211: Failed to create a P2P Device interface %s",
908634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				   ifname);
908734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			return -1;
908834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		}
908934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
909034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		drv->global->if_add_wdevid = p2pdev_info.wdev_id;
909134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		drv->global->if_add_wdevid_set = p2pdev_info.wdev_id_set;
909234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (!is_zero_ether_addr(p2pdev_info.macaddr))
909334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			os_memcpy(if_addr, p2pdev_info.macaddr, ETH_ALEN);
909434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: New P2P Device interface %s (0x%llx) created",
909534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   ifname,
909634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			   (long long unsigned int) p2pdev_info.wdev_id);
909734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	} else {
909834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
909934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					     0, NULL, NULL);
910034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (ifidx < 0) {
91018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
910234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			os_free(new_bss);
91038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
910434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			return -1;
910534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		}
91068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
91078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
910834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (!addr) {
910934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
911034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			os_memcpy(if_addr, bss->addr, ETH_ALEN);
911134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
911234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt					    bss->ifname, if_addr) < 0) {
911334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			nl80211_remove_iface(drv, ifidx);
911434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			return -1;
911534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		}
91168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
91178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
91188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
91198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!addr &&
91208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
91218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	     type == WPA_IF_P2P_GO)) {
91228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Enforce unique P2P Interface Address */
912334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		u8 new_addr[ETH_ALEN];
91248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
912534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
91261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				       new_addr) < 0) {
91278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nl80211_remove_iface(drv, ifidx);
91288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
91298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
913034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (nl80211_addr_in_use(drv->global, new_addr)) {
91318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
91328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "for P2P group interface");
91338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (nl80211_p2p_interface_addr(drv, new_addr) < 0) {
91348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				nl80211_remove_iface(drv, ifidx);
91358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return -1;
91368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
91371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
91388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       new_addr) < 0) {
91398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				nl80211_remove_iface(drv, ifidx);
91408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return -1;
91418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
91428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
91436e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidt		os_memcpy(if_addr, new_addr, ETH_ALEN);
91448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
91458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
91468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
91478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
91488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bridge &&
91498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
91508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
91518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "interface %s to a bridge %s", ifname, bridge);
91528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_remove_iface(drv, ifidx);
91538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(new_bss);
91548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
91558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
91568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
91578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (type == WPA_IF_AP_BSS) {
91581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
91591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		{
91608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nl80211_remove_iface(drv, ifidx);
91618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(new_bss);
91628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
91638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
91648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
91651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
91668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		new_bss->ifindex = ifidx;
91678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		new_bss->drv = drv;
91688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		new_bss->next = drv->first_bss.next;
9169c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		new_bss->freq = drv->first_bss.freq;
9170a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		new_bss->ctx = bss_ctx;
91718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->first_bss.next = new_bss;
91728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (drv_priv)
91738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			*drv_priv = new_bss;
91741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_init_bss(new_bss);
9175c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
9176c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		/* Subscribe management frames for this WPA_IF_AP_BSS */
9177c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		if (nl80211_setup_ap(new_bss))
9178c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt			return -1;
91798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
91808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
91818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
91821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv->global)
91831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		drv->global->if_add_ifindex = ifidx;
91841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
91858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
91868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
91878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
91888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
91894b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
91908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					enum wpa_driver_if_type type,
91918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					const char *ifname)
91928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
91938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
91948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifindex = if_nametoindex(ifname);
91958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
91968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d",
91978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   __func__, type, ifname, ifindex);
91988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ifindex <= 0)
91998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
92008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9201aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt	nl80211_remove_iface(drv, ifindex);
9202aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt
92038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
9204aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt	if (type != WPA_IF_AP_BSS)
9205aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt		return 0;
9206aa532510a7b8c4da2d7d6e2c11dda5db840894e4Dmitry Shmidt
92078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss->added_if_into_bridge) {
92081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
92091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				    bss->ifname) < 0)
92108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
92118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "interface %s from bridge %s: %s",
92128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   bss->ifname, bss->brname, strerror(errno));
92138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
92148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss->added_bridge) {
92151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
92168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
92178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "bridge %s: %s",
92188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   bss->brname, strerror(errno));
92198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
92208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
92218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss != &drv->first_bss) {
92228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct i802_bss *tbss;
92238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
92248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (tbss = &drv->first_bss; tbss; tbss = tbss->next) {
92258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (tbss->next == bss) {
92268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				tbss->next = bss->next;
9227c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				/* Unsubscribe management frames */
9228c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt				nl80211_teardown_ap(bss);
92291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				nl80211_destroy_bss(bss);
92308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				os_free(bss);
92318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				bss = NULL;
92328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
92338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
92348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
92358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (bss)
92368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "nl80211: %s - could not find "
92378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "BSS %p in the list", __func__, bss);
92388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
92398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
92408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
92418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
92428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
92438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
92448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
92458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int cookie_handler(struct nl_msg *msg, void *arg)
92468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
92478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
92488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
92498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u64 *cookie = arg;
92508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
92518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
92528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_COOKIE])
92538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
92548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
92558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
92568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
92578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
92581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_send_frame_cmd(struct i802_bss *bss,
92598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  unsigned int freq, unsigned int wait,
92608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  const u8 *buf, size_t buf_len,
92611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				  u64 *cookie_out, int no_cck, int no_ack,
92621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				  int offchanok)
92638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
92641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
92658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
92668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u64 cookie;
92678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
92688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
92698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
92708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
92718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
92728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
92738da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	wpa_printf(MSG_MSGDUMP, "nl80211: CMD_FRAME freq=%u wait=%u no_cck=%d "
927404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		   "no_ack=%d offchanok=%d",
927504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		   freq, wait, no_cck, no_ack, offchanok);
9276c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "CMD_FRAME", buf, buf_len);
92771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
92788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
927934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (nl80211_set_iface_id(msg, bss) < 0)
928034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		goto nla_put_failure;
9281c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt	if (freq)
9282c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
92836e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidt	if (wait)
92846e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
9285c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	if (offchanok && (drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX))
92861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
92871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (no_cck)
92881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
92891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (no_ack)
92901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK);
92911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
92928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf);
92938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
92948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cookie = 0;
92958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
92968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
92978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
92988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
92996e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidt			   "(%s) (freq=%u wait=%u)", ret, strerror(-ret),
93006e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidt			   freq, wait);
93018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
93028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
93038da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	wpa_printf(MSG_MSGDUMP, "nl80211: Frame TX command accepted%s; "
93041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   "cookie 0x%llx", no_ack ? " (no ACK)" : "",
93051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   (long long unsigned int) cookie);
93068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
93078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cookie_out)
93081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		*cookie_out = no_ack ? (u64) -1 : cookie;
93098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
93108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
93118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
93128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
93138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
93148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
93158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
93164b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int wpa_driver_nl80211_send_action(struct i802_bss *bss,
93174b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					  unsigned int freq,
93188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  unsigned int wait_time,
93198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  const u8 *dst, const u8 *src,
93208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  const u8 *bssid,
93211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					  const u8 *data, size_t data_len,
93221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					  int no_cck)
93238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
93248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
93258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
93268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *buf;
93278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee80211_hdr *hdr;
93288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
93298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
9330c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		   "freq=%u MHz wait=%d ms no_cck=%d)",
9331c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		   drv->ifindex, freq, wait_time, no_cck);
93328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
93338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = os_zalloc(24 + data_len);
93348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
93358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ret;
93368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(buf + 24, data, data_len);
93378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = (struct ieee80211_hdr *) buf;
93388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr->frame_control =
93398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
93408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(hdr->addr1, dst, ETH_ALEN);
93418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(hdr->addr2, src, ETH_ALEN);
93428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(hdr->addr3, bssid, ETH_ALEN);
93438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
93441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (is_ap_interface(drv->nlmode))
93454b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt		ret = wpa_driver_nl80211_send_mlme(bss, buf, 24 + data_len,
93464b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt						   0, freq, no_cck, 1,
93474b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt						   wait_time);
93488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
93491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
93508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     24 + data_len,
93511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					     &drv->send_action_cookie,
93521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					     no_cck, 0, 1);
93538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
93548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(buf);
93558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
93568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
93578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
93588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
93598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
93608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
93618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
93628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
93638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
93648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
93658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
93668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
93678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
93688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
93698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
93702f3b8dec59373945c5feef8a78ced8967a80cc66Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Cancel TX frame wait: cookie=0x%llx",
93712f3b8dec59373945c5feef8a78ced8967a80cc66Dmitry Shmidt		   (long long unsigned int) drv->send_action_cookie);
93721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL);
93738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
937434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (nl80211_set_iface_id(msg, bss) < 0)
937534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		goto nla_put_failure;
93768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie);
93778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
93788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
93798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
93808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret)
93818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
93828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", ret, strerror(-ret));
93838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
93848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
93858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
93868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
93878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
93888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
93898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
93908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						unsigned int duration)
93918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
93928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
93938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
93948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
93958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
93968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u64 cookie;
93978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
93988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
93998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
94008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
94018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
94021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL);
94038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
940434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (nl80211_set_iface_id(msg, bss) < 0)
940534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		goto nla_put_failure;
940634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
94078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
94088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
94098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
94108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cookie = 0;
94118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
94121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
94138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == 0) {
94148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
94158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "0x%llx for freq=%u MHz duration=%u",
94168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (long long unsigned int) cookie, freq, duration);
94178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->remain_on_chan_cookie = cookie;
94181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		drv->pending_remain_on_chan = 1;
94198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
94208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
94218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
94228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "(freq=%d duration=%u): %d (%s)",
94238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   freq, duration, ret, strerror(-ret));
94248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
94251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
94268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
94278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
94288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
94298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
94308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
94318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
94328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
94338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
94348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
94358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
94368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
94378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!drv->pending_remain_on_chan) {
94388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: No pending remain-on-channel "
94398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "to cancel");
94408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
94418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
94428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
94438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Cancel remain-on-channel with cookie "
94448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "0x%llx",
94458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (long long unsigned int) drv->remain_on_chan_cookie);
94468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
94478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
94488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
94498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
94508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
94511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
94528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
945334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (nl80211_set_iface_id(msg, bss) < 0)
945434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		goto nla_put_failure;
945534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
94568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
94578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
94588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
94591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = NULL;
94608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == 0)
94618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
94628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
94638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "%d (%s)", ret, strerror(-ret));
94648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
94651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
94668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
94678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
94688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
94698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
94704b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
94718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
94728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
94736e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidt
94748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!report) {
94751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (bss->nl_preq && drv->device_ap_sme &&
94761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    is_ap_interface(drv->nlmode)) {
94771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			/*
94781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 * Do not disable Probe Request reporting that was
94791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 * enabled in nl80211_setup_ap().
94801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 */
94811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Skip disabling of "
94821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "Probe Request reporting nl_preq=%p while "
94831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "in AP mode", bss->nl_preq);
94841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		} else if (bss->nl_preq) {
94851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
94861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   "reporting nl_preq=%p", bss->nl_preq);
94878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			eloop_unregister_read_sock(
94881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				nl_socket_get_fd(bss->nl_preq));
94891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			nl_destroy_handles(&bss->nl_preq);
94908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
94918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
94928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
94938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
94941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (bss->nl_preq) {
94958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting "
94961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "already on! nl_preq=%p", bss->nl_preq);
94978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
94988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
94998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
95001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	bss->nl_preq = nl_create_handle(drv->global->nl_cb, "preq");
95011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (bss->nl_preq == NULL)
95028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
95031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Enable Probe Request "
95041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   "reporting nl_preq=%p", bss->nl_preq);
95058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
95061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (nl80211_register_frame(bss, bss->nl_preq,
95078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   (WLAN_FC_TYPE_MGMT << 2) |
95088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   (WLAN_FC_STYPE_PROBE_REQ << 4),
95091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   NULL, 0) < 0)
95101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto out_err;
9511497c1d5e50162d6b3c1cce5dbd9c5fd9da69aaefDmitry Shmidt
95121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	eloop_register_read_sock(nl_socket_get_fd(bss->nl_preq),
95131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				 wpa_driver_nl80211_event_receive, bss->nl_cb,
95141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				 bss->nl_preq);
95158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
95168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
95178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
95181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt out_err:
95191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_destroy_handles(&bss->nl_preq);
95208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
95218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
95228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
95238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
95248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
95258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     int ifindex, int disabled)
95268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
95278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
95288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *bands, *band;
95298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
95308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
95318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
95328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
95338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
95348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
95351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_TX_BITRATE_MASK);
95368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
95378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
95388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
95398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!bands)
95408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
95418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
95428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
95438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything
95448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS
95458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * rates. All 5 GHz rates are left enabled.
95468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
95478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	band = nla_nest_start(msg, NL80211_BAND_2GHZ);
95488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!band)
95498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
95501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (disabled) {
95511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
95521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			"\x0c\x12\x18\x24\x30\x48\x60\x6c");
95531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
95548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_nest_end(msg, band);
95558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
95568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_nest_end(msg, bands);
95578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
95588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
95598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
95608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
95618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
95628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", ret, strerror(-ret));
956361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	} else
956461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		drv->disabled_11b_rates = disabled;
956561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
95668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
95678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
95688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
95698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
95708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
95718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
95728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
95738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
95748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_deinit_ap(void *priv)
95758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
95768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
95778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
95781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!is_ap_interface(drv->nlmode))
95798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
95808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_driver_nl80211_del_beacon(drv);
9581b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
9582b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	/*
9583b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	 * If the P2P GO interface was dynamically added, then it is
9584b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	 * possible that the interface change to station is not possible.
9585b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	 */
9586b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (drv->nlmode == NL80211_IFTYPE_P2P_GO && bss->if_dynamic)
9587b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return 0;
9588b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
95891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
95908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
95918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
95928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9593ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidtstatic int wpa_driver_nl80211_stop_ap(void *priv)
9594ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt{
9595ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	struct i802_bss *bss = priv;
9596ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
9597ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	if (!is_ap_interface(drv->nlmode))
9598ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		return -1;
9599ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	wpa_driver_nl80211_del_beacon(drv);
9600ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	bss->beacon_set = 0;
9601ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	return 0;
9602ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt}
9603ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
9604ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
960504949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic int wpa_driver_nl80211_deinit_p2p_cli(void *priv)
960604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
960704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct i802_bss *bss = priv;
960804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
960904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (drv->nlmode != NL80211_IFTYPE_P2P_CLIENT)
961004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return -1;
9611b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
9612b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	/*
9613b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	 * If the P2P Client interface was dynamically added, then it is
9614b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	 * possible that the interface change to station is not possible.
9615b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	 */
9616b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (bss->if_dynamic)
9617b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return 0;
9618b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
961904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
962004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
962104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
962204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
96238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_resume(void *priv)
96248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
96258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
962634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
962734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (i802_set_iface_flags(bss, 1))
962834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on resume event");
96298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
96308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
96318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
96328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
96338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  const u8 *ies, size_t ies_len)
96348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
96358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
96368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
96378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
96388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *data, *pos;
96398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t data_len;
96401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	const u8 *own_addr = bss->addr;
96418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
96428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (action != 1) {
96438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action "
96448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "action %d", action);
96458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
96468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
96478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
96488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
96498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Action frame payload:
96508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Category[1] = 6 (Fast BSS Transition)
96518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Action[1] = 1 (Fast BSS Transition Request)
96528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * STA Address
96538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Target AP Address
96548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * FT IEs
96558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
96568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
96578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data_len = 2 + 2 * ETH_ALEN + ies_len;
96588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data = os_malloc(data_len);
96598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data == NULL)
96608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
96618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = data;
96628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*pos++ = 0x06; /* FT Action category */
96638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*pos++ = action;
96648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, own_addr, ETH_ALEN);
96658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += ETH_ALEN;
96668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, target_ap, ETH_ALEN);
96678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += ETH_ALEN;
96688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, ies, ies_len);
96698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
96708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0,
96718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     drv->bssid, own_addr, drv->bssid,
96721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt					     data, data_len, 0);
96738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(data);
96748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
96758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
96768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
96778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
96788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
96798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
96808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
96818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
96828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
96838da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	struct nl_msg *msg;
96848da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	struct nlattr *cqm;
968561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	int ret = -1;
96868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
96878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
96888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "hysteresis=%d", threshold, hysteresis);
96898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
96908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
96918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
96928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
96938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
96941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_CQM);
96958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
96968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
96978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
96988da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	cqm = nla_nest_start(msg, NL80211_ATTR_CQM);
96998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cqm == NULL)
970061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		goto nla_put_failure;
97018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
97028da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
97038da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
97048da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt	nla_nest_end(msg, cqm);
97058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
970661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
97078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
97088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
97098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
97108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
971161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return ret;
97128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
97138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
97148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
971534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt/* Converts nl80211_chan_width to a common format */
971634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic enum chan_width convert2width(int width)
971734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
971834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	switch (width) {
971934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case NL80211_CHAN_WIDTH_20_NOHT:
972034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return CHAN_WIDTH_20_NOHT;
972134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case NL80211_CHAN_WIDTH_20:
972234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return CHAN_WIDTH_20;
972334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case NL80211_CHAN_WIDTH_40:
972434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return CHAN_WIDTH_40;
972534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case NL80211_CHAN_WIDTH_80:
972634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return CHAN_WIDTH_80;
972734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case NL80211_CHAN_WIDTH_80P80:
972834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return CHAN_WIDTH_80P80;
972934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	case NL80211_CHAN_WIDTH_160:
973034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return CHAN_WIDTH_160;
973134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
973234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return CHAN_WIDTH_UNKNOWN;
973334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
973434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
973534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
973634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int get_channel_width(struct nl_msg *msg, void *arg)
973734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
973834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
973934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
974034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wpa_signal_info *sig_change = arg;
974134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
974234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
974334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
974434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
974534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	sig_change->center_frq1 = -1;
974634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	sig_change->center_frq2 = -1;
974734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	sig_change->chanwidth = CHAN_WIDTH_UNKNOWN;
974834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
974934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (tb[NL80211_ATTR_CHANNEL_WIDTH]) {
975034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		sig_change->chanwidth = convert2width(
975134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			nla_get_u32(tb[NL80211_ATTR_CHANNEL_WIDTH]));
975234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (tb[NL80211_ATTR_CENTER_FREQ1])
975334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			sig_change->center_frq1 =
975434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
975534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		if (tb[NL80211_ATTR_CENTER_FREQ2])
975634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt			sig_change->center_frq2 =
975734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
975834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
975934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
976034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return NL_SKIP;
976134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
976234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
976334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
976434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtstatic int nl80211_get_channel_width(struct wpa_driver_nl80211_data *drv,
976534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt				     struct wpa_signal_info *sig)
976634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
976734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct nl_msg *msg;
976834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
976934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	msg = nlmsg_alloc();
977034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (!msg)
977134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return -ENOMEM;
977234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
977334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_INTERFACE);
977434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
977534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
977634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return send_and_recv_msgs(drv, msg, get_channel_width, sig);
977734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
977834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtnla_put_failure:
977934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	nlmsg_free(msg);
978034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return -ENOBUFS;
978134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
978234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
978334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
97848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
97858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
97868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
97878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
97888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res;
97898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
97908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(si, 0, sizeof(*si));
97918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = nl80211_get_link_signal(drv, si);
97928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res != 0)
97938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return res;
97948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
979534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	res = nl80211_get_channel_width(drv, si);
979634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (res != 0)
979734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return res;
979834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
97998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return nl80211_get_link_noise(drv, si);
98008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
98018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int wpa_driver_nl80211_shared_freq(void *priv)
98048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
98058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
98068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
98071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *driver;
98081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int freq = 0;
98098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/*
98111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * If the same PHY is in connected state with some other interface,
98121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * then retrieve the assoc freq.
98131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 */
98141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Get shared freq for PHY %s",
98151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   drv->phyname);
98168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	dl_list_for_each(driver, &drv->global->interfaces,
98181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			 struct wpa_driver_nl80211_data, list) {
98191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if (drv == driver ||
98201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    os_strcmp(drv->phyname, driver->phyname) != 0 ||
98211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef ANDROID_P2P
98221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    (!driver->associated && !is_ap_interface(driver->nlmode)))
98231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#else
98241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    !driver->associated)
98251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif
98261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			continue;
98278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s "
98291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   MACSTR,
98301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   driver->phyname, driver->first_bss.ifname,
98311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   MAC2STR(driver->first_bss.addr));
983204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		if (is_ap_interface(driver->nlmode))
98331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			freq = driver->first_bss.freq;
98341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		else
98351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			freq = nl80211_get_assoc_freq(driver);
98361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
98371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   drv->phyname, freq);
98381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
98398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!freq)
98411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: No shared interface for "
98421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "PHY (%s) in associated state", drv->phyname);
98438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return freq;
98451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
98468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
98481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
98491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			      int encrypt)
98501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
98511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct i802_bss *bss = priv;
9852c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0,
9853c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt					     0, 0, 0, 0);
98548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
98558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_set_param(void *priv, const char *param)
98588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
98598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: driver param='%s'", param);
98608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (param == NULL)
98618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
98628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
98648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strstr(param, "use_p2p_group_interface=1")) {
98658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct i802_bss *bss = priv;
98668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wpa_driver_nl80211_data *drv = bss->drv;
98678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
98698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "interface");
98708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
98718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
98728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
987334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
987434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (os_strstr(param, "p2p_device=1")) {
987534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		struct i802_bss *bss = priv;
987634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		struct wpa_driver_nl80211_data *drv = bss->drv;
987734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		drv->allow_p2p_device = 1;
987834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	}
987934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
98801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef ANDROID_P2P
98811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if(os_strstr(param, "use_multi_chan_concurrent=1")) {
98821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		struct i802_bss *bss = priv;
98831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		struct wpa_driver_nl80211_data *drv = bss->drv;
98841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Use Multi channel "
98851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "concurrency");
9886c2ebb4b85d69b65f552fee71ac68f44e8d87b39eDmitry Shmidt		drv->capa.num_multichan_concurrent = 2;
98871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
98881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif
98898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
98908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
98928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
98938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void * nl80211_global_init(void)
98968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
98978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl80211_global *global;
98981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct netlink_config *cfg;
98991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
99008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	global = os_zalloc(sizeof(*global));
99018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global == NULL)
99028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
99031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	global->ioctl_sock = -1;
99048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_init(&global->interfaces);
99051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	global->if_add_ifindex = -1;
99061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
99071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	cfg = os_zalloc(sizeof(*cfg));
99081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (cfg == NULL)
99091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto err;
99101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
99111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	cfg->ctx = global;
99121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
99131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
99141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	global->netlink = netlink_init(cfg);
99151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (global->netlink == NULL) {
99161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		os_free(cfg);
99171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto err;
99181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
99191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
99201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (wpa_driver_nl80211_init_nl_global(global) < 0)
99211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto err;
99221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
99231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
99241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (global->ioctl_sock < 0) {
99251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		perror("socket(PF_INET,SOCK_DGRAM)");
99261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto err;
99271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
99281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
99298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return global;
99301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
99311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidterr:
99321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_global_deinit(global);
99331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return NULL;
99348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
99358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
99368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
99378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_global_deinit(void *priv)
99388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
99398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl80211_global *global = priv;
99408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global == NULL)
99418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
99428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!dl_list_empty(&global->interfaces)) {
99438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: %u interface(s) remain at "
99448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "nl80211_global_deinit",
99458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   dl_list_len(&global->interfaces));
99468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
99471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
99481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (global->netlink)
99491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		netlink_deinit(global->netlink);
99501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
99511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_destroy_handles(&global->nl);
99521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
99531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (global->nl_event) {
99541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		eloop_unregister_read_sock(
99551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			nl_socket_get_fd(global->nl_event));
99561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl_destroy_handles(&global->nl_event);
99571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
99581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
99591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl_cb_put(global->nl_cb);
99601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
99611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (global->ioctl_sock >= 0)
99621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		close(global->ioctl_sock);
99631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
99648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(global);
99658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
99668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
99678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
99688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char * nl80211_get_radio_name(void *priv)
99698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
99708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
99718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
99728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return drv->phyname;
99738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
99748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
99758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
997675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid,
997775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			 const u8 *pmkid)
997875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
997975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct nl_msg *msg;
998075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
998175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	msg = nlmsg_alloc();
998275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (!msg)
998375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		return -ENOMEM;
998475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
99851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(bss->drv, msg, 0, cmd);
998675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
998775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
998875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (pmkid)
998975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		NLA_PUT(msg, NL80211_ATTR_PMKID, 16, pmkid);
999075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (bssid)
999175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
999275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
999375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
999475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen nla_put_failure:
99951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
999675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	return -ENOBUFS;
999775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
999875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
999975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
1000075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic int nl80211_add_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
1000175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
1000275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct i802_bss *bss = priv;
1000375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR, MAC2STR(bssid));
1000475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	return nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, bssid, pmkid);
1000575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
1000675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
1000775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
1000875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic int nl80211_remove_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
1000975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
1001075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct i802_bss *bss = priv;
1001175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
1001275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		   MAC2STR(bssid));
1001375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	return nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, bssid, pmkid);
1001475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
1001575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
1001675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
1001775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic int nl80211_flush_pmkid(void *priv)
1001875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
1001975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct i802_bss *bss = priv;
1002075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs");
1002175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	return nl80211_pmkid(bss, NL80211_CMD_FLUSH_PMKSA, NULL, NULL);
1002275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
1002375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
1002475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
10025b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic void clean_survey_results(struct survey_results *survey_results)
10026b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{
10027b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	struct freq_survey *survey, *tmp;
10028b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10029b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (dl_list_empty(&survey_results->survey_list))
10030b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return;
10031b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10032b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
10033b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			      struct freq_survey, list) {
10034b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		dl_list_del(&survey->list);
10035b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		os_free(survey);
10036b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	}
10037b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt}
10038b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10039b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10040b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic void add_survey(struct nlattr **sinfo, u32 ifidx,
10041b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		       struct dl_list *survey_list)
10042b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{
10043b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	struct freq_survey *survey;
10044b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10045b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	survey = os_zalloc(sizeof(struct freq_survey));
10046b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if  (!survey)
10047b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return;
10048b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10049b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	survey->ifidx = ifidx;
10050b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	survey->freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
10051b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	survey->filled = 0;
10052b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10053b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (sinfo[NL80211_SURVEY_INFO_NOISE]) {
10054b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		survey->nf = (int8_t)
10055b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
10056b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		survey->filled |= SURVEY_HAS_NF;
10057b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	}
10058b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10059b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]) {
10060b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		survey->channel_time =
10061b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME]);
10062b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		survey->filled |= SURVEY_HAS_CHAN_TIME;
10063b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	}
10064b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10065b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]) {
10066b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		survey->channel_time_busy =
10067b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY]);
10068b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		survey->filled |= SURVEY_HAS_CHAN_TIME_BUSY;
10069b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	}
10070b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10071b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]) {
10072b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		survey->channel_time_rx =
10073b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_RX]);
10074b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		survey->filled |= SURVEY_HAS_CHAN_TIME_RX;
10075b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	}
10076b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10077b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]) {
10078b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		survey->channel_time_tx =
10079b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			nla_get_u64(sinfo[NL80211_SURVEY_INFO_CHANNEL_TIME_TX]);
10080b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		survey->filled |= SURVEY_HAS_CHAN_TIME_TX;
10081b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	}
10082b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10083b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry 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)",
10084b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		   survey->freq,
10085b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		   survey->nf,
10086b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		   (unsigned long int) survey->channel_time,
10087b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		   (unsigned long int) survey->channel_time_busy,
10088b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		   (unsigned long int) survey->channel_time_tx,
10089b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		   (unsigned long int) survey->channel_time_rx,
10090b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		   survey->filled);
10091b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10092b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	dl_list_add_tail(survey_list, &survey->list);
10093b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt}
10094b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10095b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10096b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic int check_survey_ok(struct nlattr **sinfo, u32 surveyed_freq,
10097b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			   unsigned int freq_filter)
10098b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{
10099b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (!freq_filter)
10100b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return 1;
10101b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10102b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	return freq_filter == surveyed_freq;
10103b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt}
10104b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10105b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10106b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic int survey_handler(struct nl_msg *msg, void *arg)
10107b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{
10108b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
10109b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
10110b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
10111b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	struct survey_results *survey_results;
10112b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	u32 surveyed_freq = 0;
10113b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	u32 ifidx;
10114b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10115b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
10116b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		[NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
10117b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		[NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
10118b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	};
10119b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10120b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	survey_results = (struct survey_results *) arg;
10121b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10122b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
10123b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
10124b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10125b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
10126b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10127b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (!tb[NL80211_ATTR_SURVEY_INFO])
10128b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return NL_SKIP;
10129b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10130b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
10131b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			     tb[NL80211_ATTR_SURVEY_INFO],
10132b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			     survey_policy))
10133b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return NL_SKIP;
10134b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10135b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY]) {
10136b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Invalid survey data");
10137b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return NL_SKIP;
10138b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	}
10139b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10140b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	surveyed_freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
10141b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10142b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (!check_survey_ok(sinfo, surveyed_freq,
10143b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			     survey_results->freq_filter))
10144b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return NL_SKIP;
10145b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10146b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (survey_results->freq_filter &&
10147b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	    survey_results->freq_filter != surveyed_freq) {
10148b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		wpa_printf(MSG_EXCESSIVE, "nl80211: Ignoring survey data for freq %d MHz",
10149b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt			   surveyed_freq);
10150b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		return NL_SKIP;
10151b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	}
10152b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10153b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	add_survey(sinfo, ifidx, &survey_results->survey_list);
10154b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10155b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	return NL_SKIP;
10156b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt}
10157b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10158b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10159b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtstatic int wpa_driver_nl80211_get_survey(void *priv, unsigned int freq)
10160b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt{
10161b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	struct i802_bss *bss = priv;
10162b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
10163b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	struct nl_msg *msg;
10164b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	int err = -ENOBUFS;
10165b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	union wpa_event_data data;
10166b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	struct survey_results *survey_results;
10167b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10168b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
10169b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	survey_results = &data.survey_results;
10170b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10171b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	dl_list_init(&survey_results->survey_list);
10172b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10173b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	msg = nlmsg_alloc();
10174b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (!msg)
10175b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		goto nla_put_failure;
10176b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10177b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
10178b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10179b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
10180b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10181b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (freq)
10182b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		data.survey_results.freq_filter = freq;
10183b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10184b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	do {
10185b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Fetch survey data");
10186b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		err = send_and_recv_msgs(drv, msg, survey_handler,
10187b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt					 survey_results);
10188b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	} while (err > 0);
10189b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10190b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	if (err) {
10191b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to process survey data");
10192b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt		goto out_clean;
10193b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	}
10194b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10195b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_SURVEY, &data);
10196b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10197b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtout_clean:
10198b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	clean_survey_results(survey_results);
10199b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidtnla_put_failure:
10200b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	return err;
10201b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt}
10202b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
10203b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt
102041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
102051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				   const u8 *replay_ctr)
102061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
102071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct i802_bss *bss = priv;
102081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
102091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nlattr *replay_nested;
102101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_msg *msg;
102111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
102121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = nlmsg_alloc();
102131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!msg)
102141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
102151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
102161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
102171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
102181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
102191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
102201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
102211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!replay_nested)
102221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		goto nla_put_failure;
102231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
102241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek);
102251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck);
102261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
102271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		replay_ctr);
102281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
102291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nla_nest_end(msg, replay_nested);
102301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
102311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	send_and_recv_msgs(drv, msg, NULL, NULL);
102321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return;
102331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt nla_put_failure:
102341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
102351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
102361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
102371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
102381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
102391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				    const u8 *addr, int qos)
102401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
102411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* send data frame to poll STA and check whether
102421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	 * this frame is ACKed */
102431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct {
102441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		struct ieee80211_hdr hdr;
102451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		u16 qos_ctl;
102461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} STRUCT_PACKED nulldata;
102471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	size_t size;
102481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
102491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	/* Send data frame to poll STA and check whether this frame is ACKed */
102501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
102511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memset(&nulldata, 0, sizeof(nulldata));
102521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
102531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (qos) {
102541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nulldata.hdr.frame_control =
102551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			IEEE80211_FC(WLAN_FC_TYPE_DATA,
102561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				     WLAN_FC_STYPE_QOS_NULL);
102571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		size = sizeof(nulldata);
102581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	} else {
102591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nulldata.hdr.frame_control =
102601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			IEEE80211_FC(WLAN_FC_TYPE_DATA,
102611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				     WLAN_FC_STYPE_NULLFUNC);
102621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		size = sizeof(struct ieee80211_hdr);
102631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
102641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
102651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
102661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
102671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
102681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
102691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
102704b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0, 0, 0,
102714b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					 0, 0) < 0)
102721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
102731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   "send poll frame");
102741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
102751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
102761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
102771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				int qos)
102781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
102791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct i802_bss *bss = priv;
102801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
102811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_msg *msg;
102821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
102831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!drv->poll_command_supported) {
102841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_send_null_frame(bss, own_addr, addr, qos);
102851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
102861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
102871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
102881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = nlmsg_alloc();
102891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!msg)
102901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return;
102911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
102921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_PROBE_CLIENT);
102931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
102941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
102951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
102961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
102971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	send_and_recv_msgs(drv, msg, NULL, NULL);
102981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return;
102991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt nla_put_failure:
103001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
103011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
103021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
103031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
103041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_set_power_save(struct i802_bss *bss, int enabled)
103051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
103061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_msg *msg;
103071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
103081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = nlmsg_alloc();
103091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!msg)
103101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -ENOMEM;
103111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
103121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_SET_POWER_SAVE);
103131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
103141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE,
103151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED);
103161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
103171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtnla_put_failure:
103181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
103191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return -ENOBUFS;
103201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
103211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
103221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
103231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
103241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				     int ctwindow)
103251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
103261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct i802_bss *bss = priv;
103271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
103281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
103291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		   "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
103301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
103311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (opp_ps != -1 || ctwindow != -1)
10332c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#ifdef ANDROID_P2P
10333c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt		wpa_driver_set_p2p_ps(priv, legacy_ps, opp_ps, ctwindow);
10334c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#else
103351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1; /* Not yet supported */
10336c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt#endif
103371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
103381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (legacy_ps == -1)
103391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return 0;
103401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (legacy_ps != 0 && legacy_ps != 1)
103411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -1; /* Not yet supported */
103421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
103431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return nl80211_set_power_save(bss, legacy_ps);
103441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
103451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
103461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
10347ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidtstatic int nl80211_start_radar_detection(void *priv, int freq)
10348ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt{
10349ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	struct i802_bss *bss = priv;
10350ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
10351ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	struct nl_msg *msg;
10352ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	int ret;
10353ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
10354ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Start radar detection (CAC)");
10355ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_RADAR)) {
10356ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Driver does not support radar "
10357ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt			   "detection");
10358ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		return -1;
10359ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	}
10360ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
10361ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	msg = nlmsg_alloc();
10362ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	if (!msg)
10363ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		return -1;
10364ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
10365ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_RADAR_DETECT);
10366ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
10367ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
10368ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
10369ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	/* only HT20 is supported at this point */
10370ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, NL80211_CHAN_HT20);
10371ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
10372ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
10373ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	if (ret == 0)
10374ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		return 0;
10375ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
10376ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt		   "%d (%s)", ret, strerror(-ret));
10377ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidtnla_put_failure:
10378ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	return -1;
10379ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt}
10380ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt
103811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef CONFIG_TDLS
103821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
103831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
103841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				  u8 dialog_token, u16 status_code,
103851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				  const u8 *buf, size_t len)
103861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
103871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct i802_bss *bss = priv;
103881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
103891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_msg *msg;
103901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
103911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
103921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -EOPNOTSUPP;
103931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
103941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!dst)
103951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -EINVAL;
103961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
103971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = nlmsg_alloc();
103981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!msg)
103991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -ENOMEM;
104001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
104011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_MGMT);
104021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
104031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
104041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT_U8(msg, NL80211_ATTR_TDLS_ACTION, action_code);
104051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token);
104061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code);
104071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_IE, len, buf);
104081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
104091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
104101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
104111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtnla_put_failure:
104121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
104131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return -ENOBUFS;
104141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
104151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
104161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
104171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
104181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
104191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct i802_bss *bss = priv;
104201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
104211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct nl_msg *msg;
104221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	enum nl80211_tdls_operation nl80211_oper;
104231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
104241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
104251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -EOPNOTSUPP;
104261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
104271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	switch (oper) {
104281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case TDLS_DISCOVERY_REQ:
104291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_oper = NL80211_TDLS_DISCOVERY_REQ;
104301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
104311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case TDLS_SETUP:
104321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_oper = NL80211_TDLS_SETUP;
104331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
104341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case TDLS_TEARDOWN:
104351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_oper = NL80211_TDLS_TEARDOWN;
104361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
104371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case TDLS_ENABLE_LINK:
104381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_oper = NL80211_TDLS_ENABLE_LINK;
104391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
104401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case TDLS_DISABLE_LINK:
104411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		nl80211_oper = NL80211_TDLS_DISABLE_LINK;
104421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		break;
104431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case TDLS_ENABLE:
104441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return 0;
104451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	case TDLS_DISABLE:
104461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return 0;
104471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	default:
104481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -EINVAL;
104491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
104501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
104511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	msg = nlmsg_alloc();
104521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (!msg)
104531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return -ENOMEM;
104541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
104551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_OPER);
104561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT_U8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper);
104571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
104581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer);
104591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
104601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
104611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
104621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtnla_put_failure:
104631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	nlmsg_free(msg);
104641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return -ENOBUFS;
104651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
104661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
104671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* CONFIG TDLS */
104681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
104691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
104701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef ANDROID
104711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
104721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidttypedef struct android_wifi_priv_cmd {
104731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	char *buf;
104741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int used_len;
104751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int total_len;
104761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt} android_wifi_priv_cmd;
104771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
104781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int drv_errors = 0;
104791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
104801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
104811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
104821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv_errors++;
104831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
104841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		drv_errors = 0;
104851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
104861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
104871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
104881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
104891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
104901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int android_priv_cmd(struct i802_bss *bss, const char *cmd)
104911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
104921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
104931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct ifreq ifr;
104941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	android_wifi_priv_cmd priv_cmd;
104951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	char buf[MAX_DRV_CMD_SIZE];
104961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int ret;
104971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
104981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memset(&ifr, 0, sizeof(ifr));
104991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memset(&priv_cmd, 0, sizeof(priv_cmd));
105001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
105011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
105021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memset(buf, 0, sizeof(buf));
105031f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_strlcpy(buf, cmd, sizeof(buf));
105041f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
105051f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	priv_cmd.buf = buf;
105061f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	priv_cmd.used_len = sizeof(buf);
105071f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	priv_cmd.total_len = sizeof(buf);
105081f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ifr.ifr_data = &priv_cmd;
105091f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
105101f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
105111f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ret < 0) {
105121f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
105131f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   __func__);
105141f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_driver_send_hang_msg(drv);
105151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return ret;
105161f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
105171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
105181f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv_errors = 0;
105191f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return 0;
105201f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
105211f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
105221f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
105231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int android_pno_start(struct i802_bss *bss,
105241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			     struct wpa_driver_scan_params *params)
105251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
105261f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
105271f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	struct ifreq ifr;
105281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	android_wifi_priv_cmd priv_cmd;
105291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	int ret = 0, i = 0, bp;
105301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	char buf[WEXT_PNO_MAX_COMMAND_SIZE];
105311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
105321f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	bp = WEXT_PNOSETUP_HEADER_SIZE;
105331f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
105341f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	buf[bp++] = WEXT_PNO_TLV_PREFIX;
105351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	buf[bp++] = WEXT_PNO_TLV_VERSION;
105361f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
105371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	buf[bp++] = WEXT_PNO_TLV_RESERVED;
105381f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
105391f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
105401f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		/* Check that there is enough space needed for 1 more SSID, the
105411f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * other sections and null termination */
105421f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
105431f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		     WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
105441f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			break;
105451f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
105461f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				  params->ssids[i].ssid,
105471f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt				  params->ssids[i].ssid_len);
105481f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		buf[bp++] = WEXT_PNO_SSID_SECTION;
105491f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		buf[bp++] = params->ssids[i].ssid_len;
105501f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		os_memcpy(&buf[bp], params->ssids[i].ssid,
105511f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			  params->ssids[i].ssid_len);
105521f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		bp += params->ssids[i].ssid_len;
105531f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		i++;
105541f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
105551f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
105561f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
105571f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
105581f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    WEXT_PNO_SCAN_INTERVAL);
105591f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
105601f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
105611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	buf[bp++] = WEXT_PNO_REPEAT_SECTION;
105621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
105631f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    WEXT_PNO_REPEAT);
105641f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	bp += WEXT_PNO_REPEAT_LENGTH;
105651f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
105661f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
105671f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
105681f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		    WEXT_PNO_MAX_REPEAT);
105691f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
105701f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
105711f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	memset(&ifr, 0, sizeof(ifr));
105721f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	memset(&priv_cmd, 0, sizeof(priv_cmd));
105731f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
105741f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
105751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	priv_cmd.buf = buf;
105761f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	priv_cmd.used_len = bp;
105771f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	priv_cmd.total_len = bp;
105781f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ifr.ifr_data = &priv_cmd;
105791f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
105801f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
105811f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
105821f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	if (ret < 0) {
105831f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
105841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt			   ret);
105851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		wpa_driver_send_hang_msg(drv);
105861f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		return ret;
105871f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	}
105881f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
105891f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	drv_errors = 0;
105901f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
105911f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return android_priv_cmd(bss, "PNOFORCE 1");
105921f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
105931f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
105941f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
105951f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic int android_pno_stop(struct i802_bss *bss)
105961f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt{
105971f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	return android_priv_cmd(bss, "PNOFORCE 0");
105981f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt}
105991f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
106001f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* ANDROID */
106011f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
106021f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt
106034b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int driver_nl80211_set_key(const char *ifname, void *priv,
106044b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt				  enum wpa_alg alg, const u8 *addr,
106054b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt				  int key_idx, int set_tx,
106064b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt				  const u8 *seq, size_t seq_len,
106074b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt				  const u8 *key, size_t key_len)
106084b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
106094b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct i802_bss *bss = priv;
106104b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	return wpa_driver_nl80211_set_key(ifname, bss, alg, addr, key_idx,
106114b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					  set_tx, seq, seq_len, key, key_len);
106124b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
106134b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
106144b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
106154b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int driver_nl80211_scan2(void *priv,
106164b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt				struct wpa_driver_scan_params *params)
106174b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
106184b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct i802_bss *bss = priv;
106194b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	return wpa_driver_nl80211_scan(bss, params);
106204b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
106214b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
106224b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
106234b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int driver_nl80211_deauthenticate(void *priv, const u8 *addr,
106244b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					 int reason_code)
106254b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
106264b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct i802_bss *bss = priv;
106274b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	return wpa_driver_nl80211_deauthenticate(bss, addr, reason_code);
106284b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
106294b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
106304b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
106314b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int driver_nl80211_authenticate(void *priv,
106324b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt				       struct wpa_driver_auth_params *params)
106334b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
106344b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct i802_bss *bss = priv;
106354b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	return wpa_driver_nl80211_authenticate(bss, params);
106364b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
106374b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
106384b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
106394b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic void driver_nl80211_deinit(void *priv)
106404b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
106414b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct i802_bss *bss = priv;
106424b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	wpa_driver_nl80211_deinit(bss);
106434b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
106444b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
106454b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
106464b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
106474b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt				    const char *ifname)
106484b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
106494b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct i802_bss *bss = priv;
106504b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	return wpa_driver_nl80211_if_remove(bss, type, ifname);
106514b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
106524b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
106534b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
106544b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int driver_nl80211_send_mlme(void *priv, const u8 *data,
106554b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt				    size_t data_len, int noack)
106564b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
106574b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct i802_bss *bss = priv;
106584b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
106594b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					    0, 0, 0, 0);
106604b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
106614b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
106624b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
106634b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int driver_nl80211_sta_remove(void *priv, const u8 *addr)
106644b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
106654b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct i802_bss *bss = priv;
106664b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	return wpa_driver_nl80211_sta_remove(bss, addr);
106674b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
106684b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
106694b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
106704b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt#if defined(HOSTAPD) || defined(CONFIG_AP)
106714b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int driver_nl80211_set_sta_vlan(void *priv, const u8 *addr,
106724b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt				       const char *ifname, int vlan_id)
106734b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
106744b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct i802_bss *bss = priv;
106754b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	return i802_set_sta_vlan(bss, addr, ifname, vlan_id);
106764b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
106774b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt#endif /* HOSTAPD || CONFIG_AP */
106784b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
106794b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
106804b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int driver_nl80211_read_sta_data(void *priv,
106814b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					struct hostap_sta_driver_data *data,
106824b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					const u8 *addr)
106834b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
106844b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct i802_bss *bss = priv;
106854b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	return i802_read_sta_data(bss, data, addr);
106864b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
106874b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
106884b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
106894b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int driver_nl80211_send_action(void *priv, unsigned int freq,
106904b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt				      unsigned int wait_time,
106914b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt				      const u8 *dst, const u8 *src,
106924b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt				      const u8 *bssid,
106934b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt				      const u8 *data, size_t data_len,
106944b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt				      int no_cck)
106954b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
106964b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct i802_bss *bss = priv;
106974b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	return wpa_driver_nl80211_send_action(bss, freq, wait_time, dst, src,
106984b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt					      bssid, data, data_len, no_cck);
106994b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
107004b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
107014b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
107024b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidtstatic int driver_nl80211_probe_req_report(void *priv, int report)
107034b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt{
107044b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	struct i802_bss *bss = priv;
107054b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	return wpa_driver_nl80211_probe_req_report(bss, report);
107064b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt}
107074b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
107084b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt
10709700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidtstatic int wpa_driver_nl80211_update_ft_ies(void *priv, const u8 *md,
10710700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt					    const u8 *ies, size_t ies_len)
10711700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt{
10712700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	int ret;
10713700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	struct nl_msg *msg;
10714700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	struct i802_bss *bss = priv;
10715700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
10716700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	u16 mdid = WPA_GET_LE16(md);
10717700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
10718700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	msg = nlmsg_alloc();
10719700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	if (!msg)
10720700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt		return -ENOMEM;
10721700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
10722700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Updating FT IEs");
10723700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	nl80211_cmd(drv, msg, 0, NL80211_CMD_UPDATE_FT_IES);
10724700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
10725700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_IE, ies_len, ies);
10726700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	NLA_PUT_U16(msg, NL80211_ATTR_MDID, mdid);
10727700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
10728700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
10729700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	if (ret) {
10730700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: update_ft_ies failed "
10731700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt			   "err=%d (%s)", ret, strerror(-ret));
10732700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	}
10733700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
10734700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	return ret;
10735700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
10736700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidtnla_put_failure:
10737700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	nlmsg_free(msg);
10738700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	return -ENOBUFS;
10739700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt}
10740700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
10741700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt
1074234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidtconst u8 * wpa_driver_nl80211_get_macaddr(void *priv)
1074334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt{
1074434af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct i802_bss *bss = priv;
1074534af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
1074634af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
1074734af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE)
1074834af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt		return NULL;
1074934af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
1075034af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	return bss->addr;
1075134af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt}
1075234af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
1075334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt
107548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst struct wpa_driver_ops wpa_driver_nl80211_ops = {
107558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.name = "nl80211",
107568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.desc = "Linux nl80211/cfg80211",
107578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_bssid = wpa_driver_nl80211_get_bssid,
107588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_ssid = wpa_driver_nl80211_get_ssid,
107594b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.set_key = driver_nl80211_set_key,
107604b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.scan2 = driver_nl80211_scan2,
107611f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	.sched_scan = wpa_driver_nl80211_sched_scan,
107621f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	.stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
107638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_scan_results2 = wpa_driver_nl80211_get_scan_results,
107644b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.deauthenticate = driver_nl80211_deauthenticate,
107654b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.authenticate = driver_nl80211_authenticate,
107668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.associate = wpa_driver_nl80211_associate,
107678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.global_init = nl80211_global_init,
107688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.global_deinit = nl80211_global_deinit,
107698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.init2 = wpa_driver_nl80211_init,
107704b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.deinit = driver_nl80211_deinit,
107718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_capa = wpa_driver_nl80211_get_capa,
107728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_operstate = wpa_driver_nl80211_set_operstate,
107738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_supp_port = wpa_driver_nl80211_set_supp_port,
107748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_country = wpa_driver_nl80211_set_country,
107751f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	.set_ap = wpa_driver_nl80211_set_ap,
107768bae4138a0356709720a96f3e50b4d734e532c12Dmitry Shmidt	.set_acl = wpa_driver_nl80211_set_acl,
107778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.if_add = wpa_driver_nl80211_if_add,
107784b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.if_remove = driver_nl80211_if_remove,
107794b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.send_mlme = driver_nl80211_send_mlme,
107808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
107818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.sta_add = wpa_driver_nl80211_sta_add,
107824b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.sta_remove = driver_nl80211_sta_remove,
107838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
107848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.sta_set_flags = wpa_driver_nl80211_sta_set_flags,
107858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
107868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.hapd_init = i802_init,
107878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.hapd_deinit = i802_deinit,
1078875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	.set_wds_sta = i802_set_wds_sta,
1078975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen#endif /* HOSTAPD */
1079075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen#if defined(HOSTAPD) || defined(CONFIG_AP)
107918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_seqnum = i802_get_seqnum,
107928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.flush = i802_flush,
107938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_inact_sec = i802_get_inact_sec,
107948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.sta_clear_stats = i802_sta_clear_stats,
107958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_rts = i802_set_rts,
107968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_frag = i802_set_frag,
107978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_tx_queue_params = i802_set_tx_queue_params,
107984b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.set_sta_vlan = driver_nl80211_set_sta_vlan,
107998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.sta_deauth = i802_sta_deauth,
108008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.sta_disassoc = i802_sta_disassoc,
108018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD || CONFIG_AP */
108024b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.read_sta_data = driver_nl80211_read_sta_data,
108038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_freq = i802_set_freq,
108044b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.send_action = driver_nl80211_send_action,
108058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
108068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.remain_on_channel = wpa_driver_nl80211_remain_on_channel,
108078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.cancel_remain_on_channel =
108088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_driver_nl80211_cancel_remain_on_channel,
108094b9d52f502481b258fec743c03a5e957e5605afcDmitry Shmidt	.probe_req_report = driver_nl80211_probe_req_report,
108108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.deinit_ap = wpa_driver_nl80211_deinit_ap,
1081104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	.deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
108128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.resume = wpa_driver_nl80211_resume,
108138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.send_ft_action = nl80211_send_ft_action,
108148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.signal_monitor = nl80211_signal_monitor,
108158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.signal_poll = nl80211_signal_poll,
108168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.send_frame = nl80211_send_frame,
108171f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	.shared_freq = wpa_driver_nl80211_shared_freq,
108188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_param = nl80211_set_param,
108198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_radio_name = nl80211_get_radio_name,
1082075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	.add_pmkid = nl80211_add_pmkid,
1082175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	.remove_pmkid = nl80211_remove_pmkid,
1082275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	.flush_pmkid = nl80211_flush_pmkid,
108231f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	.set_rekey_info = nl80211_set_rekey_info,
108241f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	.poll_client = nl80211_poll_client,
108251f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	.set_p2p_powersave = nl80211_set_p2p_powersave,
10826ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	.start_dfs_cac = nl80211_start_radar_detection,
10827ea69e84a6f4455c59348485895d3d5e3af77a65bDmitry Shmidt	.stop_ap = wpa_driver_nl80211_stop_ap,
108281f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef CONFIG_TDLS
108291f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	.send_tdls_mgmt = nl80211_send_tdls_mgmt,
108301f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	.tdls_oper = nl80211_tdls_oper,
108311f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#endif /* CONFIG_TDLS */
10832700a137ab366edc72e371da68ba187b4717ee660Dmitry Shmidt	.update_ft_ies = wpa_driver_nl80211_update_ft_ies,
1083334af306c42b7ccf956508e7cd23f0ba90606e360Dmitry Shmidt	.get_mac_addr = wpa_driver_nl80211_get_macaddr,
10834b7b4d0ec07161a6d76c40ba7ef1306e82fbb7e15Dmitry Shmidt	.get_survey = wpa_driver_nl80211_get_survey,
108351f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt#ifdef ANDROID_P2P
108366e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidt	.set_noa = wpa_driver_set_p2p_noa,
108371f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	.get_noa = wpa_driver_get_p2p_noa,
108386e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidt	.set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
108396e933c1e09094a8972ef1e782c57f8b3c55c91d0Dmitry Shmidt#endif
10840738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidt#ifdef ANDROID
10841738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidt	.driver_cmd = wpa_driver_nl80211_driver_cmd,
10842738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidt#endif
108438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
10844