driver_nl80211.c revision 738a26e9e2087b0d43eba3534535632b27b49947
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Driver interaction with Linux nl80211/cfg80211
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2002-2010, 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 *
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This program is free software; you can redistribute it and/or modify
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * it under the terms of the GNU General Public License version 2 as
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * published by the Free Software Foundation.
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * license.
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * See README and COPYING for more details.
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <sys/ioctl.h>
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <sys/types.h>
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <sys/stat.h>
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <fcntl.h>
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <net/if.h>
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <netlink/genl/genl.h>
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <netlink/genl/family.h>
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <netlink/genl/ctrl.h>
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <linux/rtnetlink.h>
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <netpacket/packet.h>
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include <linux/filter.h>
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "nl80211_copy.h"
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eloop.h"
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/list.h"
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_defs.h"
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "netlink.h"
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "linux_ioctl.h"
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "radiotap.h"
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "radiotap_iter.h"
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "rfkill.h"
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "driver.h"
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_LIBNL20
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* libnl 2.0 compatibility code */
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define nl_handle nl_sock
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define nl80211_handle_alloc nl_socket_alloc_cb
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define nl80211_handle_destroy nl_socket_free
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * libnl 1.1 has a bug, it tries to allocate socket numbers densely
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * but when you free a socket again it will mess up its bitmap and
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * and use the wrong number the next time it needs a socket ID.
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Therefore, we wrap the handle alloc/destroy and add our own pid
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * accounting.
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic uint32_t port_bitmap[32] = { 0 };
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct nl_handle *nl80211_handle_alloc(void *cb)
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_handle *handle;
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uint32_t pid = getpid() & 0x3FFFFF;
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	handle = nl_handle_alloc_cb(cb);
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < 1024; i++) {
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (port_bitmap[i / 32] & (1 << (i % 32)))
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		port_bitmap[i / 32] |= 1 << (i % 32);
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pid += i << 22;
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_socket_set_local_port(handle, pid);
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return handle;
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_handle_destroy(struct nl_handle *handle)
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	uint32_t port = nl_socket_get_local_port(handle);
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	port >>= 22;
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	port_bitmap[port / 32] &= ~(1 << (port % 32));
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_handle_destroy(handle);
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_LIBNL20 */
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef IFF_LOWER_UP
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define IFF_LOWER_UP   0x10000         /* driver signals L1 up         */
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef IFF_DORMANT
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define IFF_DORMANT    0x20000         /* driver signals dormant       */
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef IF_OPER_DORMANT
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define IF_OPER_DORMANT 5
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef IF_OPER_UP
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define IF_OPER_UP 6
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct nl80211_global {
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct dl_list interfaces;
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct i802_bss {
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv;
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *next;
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifindex;
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char ifname[IFNAMSIZ + 1];
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char brname[IFNAMSIZ];
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int beacon_set:1;
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int added_if_into_bridge:1;
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int added_bridge:1;
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wpa_driver_nl80211_data {
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl80211_global *global;
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct dl_list list;
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 addr[ETH_ALEN];
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char phyname[32];
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *ctx;
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct netlink_data *netlink;
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ioctl_sock; /* socket for ioctl() use */
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifindex;
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int if_removed;
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int if_disabled;
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rfkill_data *rfkill;
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_capa capa;
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int has_capability;
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int operstate;
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int scan_complete_events;
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_handle *nl_handle;
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_handle *nl_handle_event;
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_handle *nl_handle_preq;
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_cache *nl_cache;
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_cache *nl_cache_event;
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_cache *nl_cache_preq;
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_cb *nl_cb;
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genl_family *nl80211;
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 auth_bssid[ETH_ALEN];
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 bssid[ETH_ALEN];
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int associated;
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 ssid[32];
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t ssid_len;
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int nlmode;
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ap_scan_as_station;
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int assoc_freq;
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int monitor_sock;
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int monitor_ifidx;
160c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	int no_monitor_iface_capab;
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int disable_11b_rates;
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int pending_remain_on_chan:1;
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u64 remain_on_chan_cookie;
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u64 send_action_cookie;
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int last_mgmt_freq;
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_scan_filter *filter_ssids;
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t num_filter_ssids;
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss first_bss;
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int eapol_sock; /* socket for EAPOL frames */
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int default_if_indices[16];
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int *if_indices;
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int num_if_indices;
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int last_freq;
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int last_freq_ht;
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    void *timeout_ctx);
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_set_mode(void *priv, int mode);
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtwpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   const u8 *addr, int cmd, u16 reason_code,
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   int local_state_change);
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_remove_monitor_interface(
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv);
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv,
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  unsigned int freq, unsigned int wait,
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  const u8 *buf, size_t buf_len, u64 *cookie);
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_probe_req_report(void *priv, int report);
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_if_remove(void *priv,
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					enum wpa_driver_if_type type,
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					const char *ifname);
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* HOSTAPD */
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
217738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidt#ifdef ANDROID
218738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidtextern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
219738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidt					 size_t buf_len);
220738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidt#endif
221738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidt
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     int ifindex, int disabled);
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv);
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinenstruct nl80211_bss_info_arg {
23087fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	struct wpa_driver_nl80211_data *drv;
23187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	struct wpa_scan_results *res;
23287fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	unsigned int assoc_freq;
23387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen};
23487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
23587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinenstatic int bss_info_handler(struct nl_msg *msg, void *arg);
23687fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
23787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* nl80211 code */
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ack_handler(struct nl_msg *msg, void *arg)
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int *err = arg;
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*err = 0;
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_STOP;
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int finish_handler(struct nl_msg *msg, void *arg)
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int *ret = arg;
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*ret = 0;
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 void *arg)
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int *ret = arg;
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*ret = err->error;
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int no_seq_check(struct nl_msg *msg, void *arg)
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_OK;
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int send_and_recv(struct wpa_driver_nl80211_data *drv,
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 struct nl_handle *nl_handle, struct nl_msg *msg,
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 int (*valid_handler)(struct nl_msg *, void *),
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 void *valid_data)
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_cb *cb;
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int err = -ENOMEM;
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cb = nl_cb_clone(drv->nl_cb);
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!cb)
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto out;
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	err = nl_send_auto_complete(nl_handle, msg);
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (err < 0)
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto out;
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	err = 1;
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (valid_handler)
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  valid_handler, valid_data);
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (err > 0)
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl_recvmsgs(nl_handle, cb);
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt out:
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cb_put(cb);
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return err;
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
303738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidtint send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      struct nl_msg *msg,
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      int (*valid_handler)(struct nl_msg *, void *),
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      void *valid_data)
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv(drv, drv->nl_handle, msg, valid_handler,
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     valid_data);
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct family_data {
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const char *group;
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int id;
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int family_handler(struct nl_msg *msg, void *arg)
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct family_data *res = arg;
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb[CTRL_ATTR_MAX + 1];
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *mcgrp;
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!tb[CTRL_ATTR_MCAST_GROUPS])
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  nla_len(mcgrp), NULL);
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       res->group,
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv,
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       const char *family, const char *group)
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct family_data res = { group, -ENOENT };
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_ctrl_resolve(drv->nl_handle, "nlctrl"),
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, 0, CTRL_CMD_GETFAMILY, 0);
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, family_handler, &res);
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == 0)
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = res.id;
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!drv->associated)
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(bssid, drv->bssid, ETH_ALEN);
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!drv->associated)
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(ssid, drv->ssid, drv->ssid_len);
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return drv->ssid_len;
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  char *buf, size_t len, int del)
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len > sizeof(event.interface_status.ifname))
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		len = sizeof(event.interface_status.ifname) - 1;
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(event.interface_status.ifname, buf, len);
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		EVENT_INTERFACE_ADDED;
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   del ? "DEL" : "NEW",
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   event.interface_status.ifname,
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   del ? "removed" : "added");
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strcmp(drv->first_bss.ifname, event.interface_status.ifname) == 0) {
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (del)
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			drv->if_removed = 1;
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			drv->if_removed = 0;
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 u8 *buf, size_t len)
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int attrlen, rta_len;
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rtattr *attr;
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	attrlen = len;
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	attr = (struct rtattr *) buf;
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rta_len = RTA_ALIGN(sizeof(struct rtattr));
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (RTA_OK(attr, attrlen)) {
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (attr->rta_type == IFLA_IFNAME) {
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (os_strcmp(((char *) attr) + rta_len, drv->first_bss.ifname)
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    == 0)
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return 1;
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		attr = RTA_NEXT(attr, attrlen);
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  int ifindex, u8 *buf, size_t len)
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->ifindex == ifindex)
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 1;
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->first_bss.ifindex = if_nametoindex(drv->first_bss.ifname);
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "interface");
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_driver_nl80211_finish_drv_init(drv);
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 1;
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 struct ifinfomsg *ifi,
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 u8 *buf, size_t len)
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = ctx;
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int attrlen, rta_len;
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rtattr *attr;
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 brid = 0;
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, buf, len) &&
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    !have_ifidx(drv, ifi->ifi_index)) {
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign "
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "ifindex %d", ifi->ifi_index);
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "(%s%s%s%s)",
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   drv->operstate, ifi->ifi_flags,
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Interface down");
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->if_disabled = 1;
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL);
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Interface up");
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->if_disabled = 0;
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL);
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Some drivers send the association event before the operup event--in
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * fails. This will hit us when wpa_supplicant does not need to do
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * IEEE 802.1X authentication
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->operstate == 1 &&
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    !(ifi->ifi_flags & IFF_RUNNING))
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		netlink_send_oper_ifla(drv->netlink, drv->ifindex,
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       -1, IF_OPER_UP);
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	attrlen = len;
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	attr = (struct rtattr *) buf;
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rta_len = RTA_ALIGN(sizeof(struct rtattr));
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (RTA_OK(attr, attrlen)) {
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (attr->rta_type == IFLA_IFNAME) {
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_driver_nl80211_event_link(
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				drv,
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				((char *) attr) + rta_len,
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				attr->rta_len - rta_len, 0);
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else if (attr->rta_type == IFLA_MASTER)
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			brid = nla_get_u32((struct nlattr *) attr);
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		attr = RTA_NEXT(attr, attrlen);
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ifi->ifi_family == AF_BRIDGE && brid) {
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* device has been added to bridge */
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		char namebuf[IFNAMSIZ];
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if_indextoname(brid, namebuf);
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   brid, namebuf);
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		add_ifidx(drv, brid);
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_event_rtm_dellink(void *ctx,
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 struct ifinfomsg *ifi,
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						 u8 *buf, size_t len)
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = ctx;
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int attrlen, rta_len;
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rtattr *attr;
5508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 brid = 0;
5518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	attrlen = len;
5538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	attr = (struct rtattr *) buf;
5548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rta_len = RTA_ALIGN(sizeof(struct rtattr));
5568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (RTA_OK(attr, attrlen)) {
5578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (attr->rta_type == IFLA_IFNAME) {
5588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_driver_nl80211_event_link(
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				drv,
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				((char *) attr) + rta_len,
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				attr->rta_len - rta_len, 1);
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else if (attr->rta_type == IFLA_MASTER)
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			brid = nla_get_u32((struct nlattr *) attr);
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		attr = RTA_NEXT(attr, attrlen);
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ifi->ifi_family == AF_BRIDGE && brid) {
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* device has been removed from bridge */
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		char namebuf[IFNAMSIZ];
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if_indextoname(brid, namebuf);
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Remove ifindex %u for bridge "
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "%s", brid, namebuf);
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		del_ifidx(drv, brid);
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    const u8 *frame, size_t len)
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ieee80211_mgmt *mgmt;
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
5858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt = (const struct ieee80211_mgmt *) frame;
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len < 24 + sizeof(mgmt->u.auth)) {
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "frame");
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(drv->auth_bssid, mgmt->sa, ETH_ALEN);
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.auth.status_code = le_to_host16(mgmt->u.auth.status_code);
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len > 24 + sizeof(mgmt->u.auth)) {
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.auth.ies = mgmt->u.auth.variable;
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth);
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinenstatic unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
60887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen{
60987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	struct nl_msg *msg;
61087fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	int ret;
61187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	struct nl80211_bss_info_arg arg;
61287fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
61387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	os_memset(&arg, 0, sizeof(arg));
61487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	msg = nlmsg_alloc();
61587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	if (!msg)
61687fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		goto nla_put_failure;
61787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
61887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, NLM_F_DUMP,
61987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		    NL80211_CMD_GET_SCAN, 0);
62087fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
62187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
62287fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	arg.drv = drv;
62387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
62487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	msg = NULL;
62587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	if (ret == 0) {
62687fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		wpa_printf(MSG_DEBUG, "nl80211: Operating frequency for the "
62787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen			   "associated BSS from scan results: %u MHz",
62887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen			   arg.assoc_freq);
62987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		return arg.assoc_freq ? arg.assoc_freq : drv->assoc_freq;
63087fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	}
63187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
63287fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		   "(%s)", ret, strerror(-ret));
63387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinennla_put_failure:
63487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	nlmsg_free(msg);
63587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	return drv->assoc_freq;
63687fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen}
63787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
63887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    const u8 *frame, size_t len)
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ieee80211_mgmt *mgmt;
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 status;
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt = (const struct ieee80211_mgmt *) frame;
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "frame");
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	status = le_to_host16(mgmt->u.assoc_resp.status_code);
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (status != WLAN_STATUS_SUCCESS) {
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memset(&event, 0, sizeof(event));
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.assoc_reject.bssid = mgmt->bssid;
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			event.assoc_reject.resp_ies =
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				(u8 *) mgmt->u.assoc_resp.variable;
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			event.assoc_reject.resp_ies_len =
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				len - 24 - sizeof(mgmt->u.assoc_resp);
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.assoc_reject.status_code = status;
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->associated = 1;
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(drv->bssid, mgmt->sa, ETH_ALEN);
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable;
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.assoc_info.resp_ies_len =
6768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			len - 24 - sizeof(mgmt->u.assoc_resp);
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.assoc_info.freq = drv->assoc_freq;
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
6868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       enum nl80211_commands cmd, struct nlattr *status,
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       struct nlattr *addr, struct nlattr *req_ie,
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       struct nlattr *resp_ie)
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Avoid reporting two association events that would confuse
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * the core code.
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Ignore connect event (cmd=%d) "
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "when using userspace SME", cmd);
6998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
7008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
7038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cmd == NL80211_CMD_CONNECT &&
7048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    nla_get_u16(status) != WLAN_STATUS_SUCCESS) {
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (addr)
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			event.assoc_reject.bssid = nla_data(addr);
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (resp_ie) {
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			event.assoc_reject.resp_ies = nla_data(resp_ie);
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			event.assoc_reject.resp_ies_len = nla_len(resp_ie);
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.assoc_reject.status_code = nla_get_u16(status);
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->associated = 1;
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (addr)
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN);
7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (req_ie) {
7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.assoc_info.req_ies = nla_data(req_ie);
7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.assoc_info.req_ies_len = nla_len(req_ie);
7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (resp_ie) {
7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.assoc_info.resp_ies = nla_data(resp_ie);
7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.assoc_info.resp_ies_len = nla_len(resp_ie);
7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
72987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	event.assoc_info.freq = nl80211_get_assoc_freq(drv);
73087fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       enum nl80211_commands cmd, struct nlattr *addr)
7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum wpa_event_type ev;
7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nla_len(addr) != ETH_ALEN)
7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR,
7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   cmd, MAC2STR((u8 *) nla_data(addr)));
7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cmd == NL80211_CMD_AUTHENTICATE)
7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ev = EVENT_AUTH_TIMED_OUT;
7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (cmd == NL80211_CMD_ASSOCIATE)
7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ev = EVENT_ASSOC_TIMED_OUT;
7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN);
7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, ev, &event);
7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_event_mgmt(struct wpa_driver_nl80211_data *drv,
7618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    struct nlattr *freq, const u8 *frame, size_t len)
7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ieee80211_mgmt *mgmt;
7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 fc, stype;
7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt = (const struct ieee80211_mgmt *) frame;
7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len < 24) {
7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Too short action frame");
7708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	fc = le_to_host16(mgmt->frame_control);
7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	stype = WLAN_FC_GET_STYPE(fc);
7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
7778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (freq) {
7788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_action.freq = nla_get_u32(freq);
7798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->last_mgmt_freq = event.rx_action.freq;
7808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (stype == WLAN_FC_STYPE_ACTION) {
7828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_action.da = mgmt->da;
7838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_action.sa = mgmt->sa;
7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_action.bssid = mgmt->bssid;
7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_action.category = mgmt->u.action.category;
7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_action.data = &mgmt->u.action.category + 1;
7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_action.len = frame + len - event.rx_action.data;
7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event);
7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_mgmt.frame = frame;
7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_mgmt.frame_len = len;
7928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_event_action_tx_status(struct wpa_driver_nl80211_data *drv,
7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					struct nlattr *cookie, const u8 *frame,
7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					size_t len, struct nlattr *ack)
8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ieee80211_hdr *hdr;
8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 fc;
8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u64 cookie_val;
8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!cookie)
8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cookie_val = nla_get_u64(cookie);
8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Action TX status: cookie=0%llx%s "
8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "(ack=%d)",
8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (long long unsigned int) cookie_val,
8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   cookie_val == drv->send_action_cookie ?
8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   " (match)" : " (unknown)", ack != NULL);
8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cookie_val != drv->send_action_cookie)
8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = (const struct ieee80211_hdr *) frame;
8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	fc = le_to_host16(hdr->frame_control);
8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.type = WLAN_FC_GET_TYPE(fc);
8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.dst = hdr->addr1;
8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.data = frame;
8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.data_len = len;
8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.ack = ack != NULL;
8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       enum wpa_event_type type,
8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       const u8 *frame, size_t len)
8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ieee80211_mgmt *mgmt;
8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *bssid = NULL;
8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 reason_code = 0;
8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt = (const struct ieee80211_mgmt *) frame;
8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len >= 24) {
8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bssid = mgmt->bssid;
8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (drv->associated != 0 &&
8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    os_memcmp(bssid, drv->bssid, ETH_ALEN) != 0 &&
8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    os_memcmp(bssid, drv->auth_bssid, ETH_ALEN) != 0) {
8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/*
8498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * We have presumably received this deauth as a
8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * response to a clear_state_mismatch() outgoing
8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * deauth.  Don't let it take us offline!
8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 */
8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Deauth received "
8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "from Unknown BSSID " MACSTR " -- ignoring",
8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   MAC2STR(bssid));
8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return;
8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->associated = 0;
8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Note: Same offset for Reason Code in both frame subtypes */
8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len >= 24 + sizeof(mgmt->u.deauth))
8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		reason_code = le_to_host16(mgmt->u.deauth.reason_code);
8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (type == EVENT_DISASSOC) {
8688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.disassoc_info.addr = bssid;
8698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.disassoc_info.reason_code = reason_code;
8708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (frame + len > mgmt->u.disassoc.variable) {
8718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			event.disassoc_info.ie = mgmt->u.disassoc.variable;
8728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			event.disassoc_info.ie_len = frame + len -
8738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				mgmt->u.disassoc.variable;
8748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
8758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
8768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.deauth_info.addr = bssid;
8778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.deauth_info.reason_code = reason_code;
8788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (frame + len > mgmt->u.deauth.variable) {
8798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			event.deauth_info.ie = mgmt->u.deauth.variable;
8808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			event.deauth_info.ie_len = frame + len -
8818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				mgmt->u.deauth.variable;
8828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
8838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, type, &event);
8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 enum wpa_event_type type,
8918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 const u8 *frame, size_t len)
8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ieee80211_mgmt *mgmt;
8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 reason_code = 0;
8968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len < 24)
8988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
8998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt = (const struct ieee80211_mgmt *) frame;
9018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
9038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Note: Same offset for Reason Code in both frame subtypes */
9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len >= 24 + sizeof(mgmt->u.deauth))
9058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		reason_code = le_to_host16(mgmt->u.deauth.reason_code);
9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (type == EVENT_UNPROT_DISASSOC) {
9088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.unprot_disassoc.sa = mgmt->sa;
9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.unprot_disassoc.da = mgmt->da;
9108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.unprot_disassoc.reason_code = reason_code;
9118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
9128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.unprot_deauth.sa = mgmt->sa;
9138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.unprot_deauth.da = mgmt->da;
9148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.unprot_deauth.reason_code = reason_code;
9158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, type, &event);
9188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_event(struct wpa_driver_nl80211_data *drv,
9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       enum nl80211_commands cmd, struct nlattr *frame,
9238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       struct nlattr *addr, struct nlattr *timed_out,
9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       struct nlattr *freq, struct nlattr *ack,
9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       struct nlattr *cookie)
9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (timed_out && addr) {
9288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_timeout_event(drv, cmd, addr);
9298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
9308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (frame == NULL) {
9338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: MLME event %d without frame "
9348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "data", cmd);
9358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
9368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: MLME event %d", cmd);
9398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_MSGDUMP, "nl80211: MLME event frame",
9408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    nla_data(frame), nla_len(frame));
9418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (cmd) {
9438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_AUTHENTICATE:
9448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_auth(drv, nla_data(frame), nla_len(frame));
9458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
9468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_ASSOCIATE:
9478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_assoc(drv, nla_data(frame), nla_len(frame));
9488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
9498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_DEAUTHENTICATE:
9508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_deauth_disassoc(drv, EVENT_DEAUTH,
9518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   nla_data(frame), nla_len(frame));
9528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
9538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_DISASSOCIATE:
9548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_deauth_disassoc(drv, EVENT_DISASSOC,
9558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   nla_data(frame), nla_len(frame));
9568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
9578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_FRAME:
9588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_mgmt(drv, freq, nla_data(frame), nla_len(frame));
9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
9608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_FRAME_TX_STATUS:
9618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_action_tx_status(drv, cookie, nla_data(frame),
9628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    nla_len(frame), ack);
9638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
9648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_UNPROT_DEAUTHENTICATE:
9658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH,
9668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     nla_data(frame), nla_len(frame));
9678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_UNPROT_DISASSOCIATE:
9698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC,
9708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     nla_data(frame), nla_len(frame));
9718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
9728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
9738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
9748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_event_michael_mic_failure(struct wpa_driver_nl80211_data *drv,
9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   struct nlattr *tb[])
9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data data;
9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure");
9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_MAC]) {
9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address",
9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    nla_data(tb[NL80211_ATTR_MAC]),
9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    nla_len(tb[NL80211_ATTR_MAC]));
9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]);
9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_KEY_SEQ]) {
9928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_DEBUG, "nl80211: TSC",
9938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    nla_data(tb[NL80211_ATTR_KEY_SEQ]),
9948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    nla_len(tb[NL80211_ATTR_KEY_SEQ]));
9958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_KEY_TYPE]) {
9978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		enum nl80211_key_type key_type =
9988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]);
9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Key Type %d", key_type);
10008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (key_type == NL80211_KEYTYPE_PAIRWISE)
10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			data.michael_mic_failure.unicast = 1;
10028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else
10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data.michael_mic_failure.unicast = 1;
10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_KEY_IDX]) {
10068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]);
10078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id);
10088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
10118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
10158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 struct nlattr *tb[])
10168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_MAC] == NULL) {
10188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
10198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "event");
10208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
10218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
10238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->associated = 1;
10248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined",
10258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   MAC2STR(drv->bssid));
10268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
10288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv,
10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 int cancel_event, struct nlattr *tb[])
10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int freq, chan_type, duration;
10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data data;
10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u64 cookie;
10378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_WIPHY_FREQ])
10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
10408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		freq = 0;
10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
10448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
10458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
10468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		chan_type = 0;
10478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_DURATION])
10498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		duration = nla_get_u32(tb[NL80211_ATTR_DURATION]);
10508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
10518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		duration = 0;
10528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_COOKIE])
10548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
10568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cookie = 0;
10578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel event (cancel=%d "
10598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))",
10608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   cancel_event, freq, chan_type, duration,
10618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (long long unsigned int) cookie,
10628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   cookie == drv->remain_on_chan_cookie ? "match" : "unknown");
10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cookie != drv->remain_on_chan_cookie)
10658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return; /* not for us */
10668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->pending_remain_on_chan = !cancel_event;
10688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
10708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.remain_on_channel.freq = freq;
10718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.remain_on_channel.duration = duration;
10728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, cancel_event ?
10738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     EVENT_CANCEL_REMAIN_ON_CHANNEL :
10748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     EVENT_REMAIN_ON_CHANNEL, &data);
10758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
10798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    struct nlattr *tb[])
10808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
10828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *nl;
10838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int rem;
10848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct scan_info *info;
10858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define MAX_REPORT_FREQS 50
10868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int freqs[MAX_REPORT_FREQS];
10878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int num_freqs = 0;
10888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
10908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	info = &event.scan_info;
10918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	info->aborted = aborted;
10928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_SCAN_SSIDS]) {
10948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) {
10958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			struct wpa_driver_scan_ssid *s =
10968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				&info->ssids[info->num_ssids];
10978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			s->ssid = nla_data(nl);
10988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			s->ssid_len = nla_len(nl);
10998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			info->num_ssids++;
11008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
11018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
11028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
11038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
11058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
11068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		{
11078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			freqs[num_freqs] = nla_get_u32(nl);
11088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			num_freqs++;
11098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (num_freqs == MAX_REPORT_FREQS - 1)
11108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
11118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
11128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		info->freqs = freqs;
11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		info->num_freqs = num_freqs;
11148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
11168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int get_link_signal(struct nl_msg *msg, void *arg)
11208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
11228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
11238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
11248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
11258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
11268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
11278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
11288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
11298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
11308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
11318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
11328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
11338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
11348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_signal_info *sig_change = arg;
11358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
11378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
11388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!tb[NL80211_ATTR_STA_INFO] ||
11398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
11408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     tb[NL80211_ATTR_STA_INFO], policy))
11418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
11428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!sinfo[NL80211_STA_INFO_SIGNAL])
11438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
11448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sig_change->current_signal =
11468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		(s8) nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
11478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
11498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
11508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     sinfo[NL80211_STA_INFO_TX_BITRATE],
11518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     rate_policy)) {
11528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			sig_change->current_txrate = 0;
11538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else {
11548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (rinfo[NL80211_RATE_INFO_BITRATE]) {
11558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				sig_change->current_txrate =
11568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					nla_get_u16(rinfo[
11578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     NL80211_RATE_INFO_BITRATE]) * 100;
11588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
11598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
11608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
11638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
11678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   struct wpa_signal_info *sig)
11688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
11708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sig->current_signal = -9999;
11728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sig->current_txrate = 0;
11738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
11758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
11768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
11778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
11798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_GET_STATION, 0);
11808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
11828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
11838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, get_link_signal, sig);
11858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
11868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
11878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int get_link_noise(struct nl_msg *msg, void *arg)
11918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
11938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
11948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
11958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
11968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
11978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
11988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
11998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_signal_info *sig_change = arg;
12008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
12028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
12038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!tb[NL80211_ATTR_SURVEY_INFO]) {
12058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: survey data missing!");
12068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
12078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
12108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     tb[NL80211_ATTR_SURVEY_INFO],
12118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     survey_policy)) {
12128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: failed to parse nested "
12138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "attributes!");
12148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
12158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
12188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
12198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
12218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    sig_change->frequency)
12228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
12238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!sinfo[NL80211_SURVEY_INFO_NOISE])
12258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
12268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sig_change->current_noise =
12288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		(s8) nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
12298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
12318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
12358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  struct wpa_signal_info *sig_change)
12368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
12388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sig_change->current_noise = 9999;
12408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sig_change->frequency = drv->assoc_freq;
12418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
12438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
12448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
12458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
12478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    NLM_F_DUMP, NL80211_CMD_GET_SURVEY, 0);
12488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
12508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, get_link_noise, sig_change);
12528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
12538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
12548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
12588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      struct nlattr *tb[])
12598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
12618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
12628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
12638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
12648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 },
12658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
12668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
12678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum nl80211_cqm_rssi_threshold_event event;
12688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data ed;
12698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_signal_info sig;
12708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res;
12718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_CQM] == NULL ||
12738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM],
12748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     cqm_policy)) {
12758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event");
12768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
12778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&ed, 0, sizeof(ed));
12808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
12828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!tb[NL80211_ATTR_MAC])
12838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return;
12848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]),
12858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  ETH_ALEN);
12868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed);
12878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
12888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
12918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
12928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
12938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) {
12958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
12968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "event: RSSI high");
12978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ed.signal_change.above_threshold = 1;
12988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) {
12998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
13008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "event: RSSI low");
13018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ed.signal_change.above_threshold = 0;
13028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else
13038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
13048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = nl80211_get_link_signal(drv, &sig);
13068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res == 0) {
13078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ed.signal_change.current_signal = sig.current_signal;
13088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ed.signal_change.current_txrate = sig.current_txrate;
13098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm  txrate: %d",
13108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   sig.current_signal, sig.current_txrate);
13118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = nl80211_get_link_noise(drv, &sig);
13148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res == 0) {
13158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ed.signal_change.current_noise = sig.current_noise;
13168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm",
13178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   sig.current_noise);
13188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed);
13218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
13258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      struct nlattr **tb)
13268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *addr;
13288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data data;
13298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_MAC] == NULL)
13318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
13328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr = nla_data(tb[NL80211_ATTR_MAC]);
13338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr));
1334c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt
1335c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	if (drv->nlmode == NL80211_IFTYPE_AP &&
1336c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	    drv->no_monitor_iface_capab) {
1337c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		u8 *ies = NULL;
1338c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		size_t ies_len = 0;
1339c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		if (tb[NL80211_ATTR_IE]) {
1340c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt			ies = nla_data(tb[NL80211_ATTR_IE]);
1341c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt			ies_len = nla_len(tb[NL80211_ATTR_IE]);
1342c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		}
1343c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Req IEs", ies, ies_len);
1344c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		drv_event_assoc(drv->ctx, addr, ies, ies_len, 0);
1345c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		return;
1346c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	}
1347c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt
13488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nlmode != NL80211_IFTYPE_ADHOC)
13498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
13508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
13528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN);
13538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_IBSS_RSN_START, &data);
13548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
13588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      struct nlattr **tb)
13598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *addr;
13618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data data;
13628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_MAC] == NULL)
13648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
13658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	addr = nla_data(tb[NL80211_ATTR_MAC]);
13668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR,
13678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   MAC2STR(addr));
1368c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt
1369c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	if (drv->nlmode == NL80211_IFTYPE_AP &&
1370c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	    drv->no_monitor_iface_capab) {
1371c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		drv_event_disassoc(drv->ctx, addr);
1372c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		return;
1373c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	}
1374c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt
13758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nlmode != NL80211_IFTYPE_ADHOC)
13768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
13778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&data, 0, sizeof(data));
13798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN);
13808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data);
13818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
13828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int process_event(struct nl_msg *msg, void *arg)
13858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
13868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = arg;
13878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
13888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
13898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data data;
13908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
13928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
13938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_IFINDEX]) {
13958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
13968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) {
13978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)"
13988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   " for foreign interface (ifindex %d)",
13998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   gnlh->cmd, ifindex);
14008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NL_SKIP;
14018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
14028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->ap_scan_as_station &&
14058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
14068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	     gnlh->cmd == NL80211_CMD_SCAN_ABORTED)) {
14078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_driver_nl80211_set_mode(&drv->first_bss,
14088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    IEEE80211_MODE_AP);
14098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->ap_scan_as_station = 0;
14108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (gnlh->cmd) {
14138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_TRIGGER_SCAN:
14148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Scan trigger");
14158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
14168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_NEW_SCAN_RESULTS:
14178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
14188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->scan_complete_events = 1;
14198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
14208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     drv->ctx);
14218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		send_scan_event(drv, 0, tb);
14228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
14238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_SCAN_ABORTED:
14248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Scan aborted");
14258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
14268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Need to indicate that scan results are available in order
14278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * not to make wpa_supplicant stop its scanning.
14288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
14298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
14308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     drv->ctx);
14318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		send_scan_event(drv, 1, tb);
14328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
14338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_AUTHENTICATE:
14348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_ASSOCIATE:
14358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_DEAUTHENTICATE:
14368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_DISASSOCIATE:
14378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_FRAME:
14388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_FRAME_TX_STATUS:
14398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_UNPROT_DEAUTHENTICATE:
14408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_UNPROT_DISASSOCIATE:
14418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event(drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
14428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_TIMED_OUT],
14438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK],
14448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   tb[NL80211_ATTR_COOKIE]);
14458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
14468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_CONNECT:
14478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_ROAM:
14488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_connect(drv, gnlh->cmd,
14498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   tb[NL80211_ATTR_STATUS_CODE],
14508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   tb[NL80211_ATTR_MAC],
14518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   tb[NL80211_ATTR_REQ_IE],
14528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   tb[NL80211_ATTR_RESP_IE]);
14538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
14548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_DISCONNECT:
14558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
14568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/*
14578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * Avoid reporting two disassociation events that could
14588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * confuse the core code.
14598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 */
14608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
14618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "event when using userspace SME");
14628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
14638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
14648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->associated = 0;
14658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memset(&data, 0, sizeof(data));
14668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tb[NL80211_ATTR_REASON_CODE])
14678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			data.disassoc_info.reason_code =
14688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				nla_get_u16(tb[NL80211_ATTR_REASON_CODE]);
14698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data);
14708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
14718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_MICHAEL_MIC_FAILURE:
14728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_michael_mic_failure(drv, tb);
14738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
14748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_JOIN_IBSS:
14758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_join_ibss(drv, tb);
14768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
14778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_REMAIN_ON_CHANNEL:
14788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_remain_on_channel(drv, 0, tb);
14798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
14808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL:
14818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mlme_event_remain_on_channel(drv, 1, tb);
14828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
14838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_NOTIFY_CQM:
14848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_cqm_event(drv, tb);
14858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
14868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_REG_CHANGE:
14878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
14888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
14898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     NULL);
14908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
14918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_REG_BEACON_HINT:
14928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
14938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
14948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     NULL);
14958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
14968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_NEW_STATION:
14978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_new_station_event(drv, tb);
14988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
14998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case NL80211_CMD_DEL_STATION:
15008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_del_station_event(drv, tb);
15018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
15028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
15038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
15048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(cmd=%d)", gnlh->cmd);
15058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
15068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
15078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
15098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
15108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
15138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     void *handle)
15148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_cb *cb;
15168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = eloop_ctx;
15178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Event message available");
15198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cb = nl_cb_clone(drv->nl_cb);
15218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!cb)
15228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
15238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
15248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, process_event, drv);
15258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_recvmsgs(handle, cb);
15268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cb_put(cb);
15278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
15288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
15318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain
15328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @priv: driver_nl80211 private data
15338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @alpha2_arg: country to which to switch to
15348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
15358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
15368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This asks nl80211 to set the regulatory domain for given
15378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * country ISO / IEC alpha2.
15388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
15398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
15408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
15428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
15438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char alpha2[3];
15448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
15458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
15478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
15488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
15498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	alpha2[0] = alpha2_arg[0];
15518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	alpha2[1] = alpha2_arg[1];
15528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	alpha2[2] = '\0';
15538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
15558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_REQ_SET_REG, 0);
15568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2);
15588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (send_and_recv_msgs(drv, msg, NULL, NULL))
15598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -EINVAL;
15608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
15618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
15628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -EINVAL;
15638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
15648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct wiphy_info_data {
15678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int max_scan_ssids;
15688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ap_supported;
15698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int p2p_supported;
15708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int auth_supported;
15718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int connect_supported;
15728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int offchan_tx_supported;
15738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int max_remain_on_chan;
15748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
15758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wiphy_info_handler(struct nl_msg *msg, void *arg)
15788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
15808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
15818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wiphy_info_data *info = arg;
15828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int p2p_go_supported = 0, p2p_client_supported = 0;
15838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
15858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
15868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
15888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		info->max_scan_ssids =
15898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS]);
15908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_SUPPORTED_IFTYPES]) {
15928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct nlattr *nl_mode;
15938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int i;
15948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_for_each_nested(nl_mode,
15958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
15968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			switch (nla_type(nl_mode)) {
15978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			case NL80211_IFTYPE_AP:
15988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				info->ap_supported = 1;
15998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
16008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			case NL80211_IFTYPE_P2P_GO:
16018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				p2p_go_supported = 1;
16028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
16038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			case NL80211_IFTYPE_P2P_CLIENT:
16048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				p2p_client_supported = 1;
16058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
16068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
16078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
16088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
16098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	info->p2p_supported = p2p_go_supported && p2p_client_supported;
16118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) {
16138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct nlattr *nl_cmd;
16148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int i;
16158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_for_each_nested(nl_cmd,
16178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) {
16188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			u32 cmd = nla_get_u32(nl_cmd);
16198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (cmd == NL80211_CMD_AUTHENTICATE)
16208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				info->auth_supported = 1;
16218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else if (cmd == NL80211_CMD_CONNECT)
16228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				info->connect_supported = 1;
16238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
16248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
16258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK])
16278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		info->offchan_tx_supported = 1;
16288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION])
16308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		info->max_remain_on_chan =
16318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nla_get_u32(tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
16328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
16348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
16358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
16388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       struct wiphy_info_data *info)
16398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
16408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
16418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(info, 0, sizeof(*info));
16438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* default to 5000 since early versions of mac80211 don't set it */
16458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	info->max_remain_on_chan = 5000;
16468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
16488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
16498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
16508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
16528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_GET_WIPHY, 0);
16538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex);
16558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info) == 0)
16578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
16588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
16598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
16608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
16618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
16628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
16638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
16668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
16678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wiphy_info_data info;
16688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_driver_nl80211_get_info(drv, &info))
16698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
16708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->has_capability = 1;
16718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
16728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
16738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
16748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
16758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
16768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->capa.enc = WPA_DRIVER_CAPA_ENC_WEP40 |
16778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_CAPA_ENC_WEP104 |
16788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_CAPA_ENC_TKIP |
16798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_CAPA_ENC_CCMP;
16808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
16818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_AUTH_SHARED |
16828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		WPA_DRIVER_AUTH_LEAP;
16838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->capa.max_scan_ssids = info.max_scan_ssids;
16858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (info.ap_supported)
16868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
16878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (info.auth_supported)
16898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->capa.flags |= WPA_DRIVER_FLAGS_SME;
16908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (!info.connect_supported) {
16918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "nl80211: Driver does not support "
16928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "authentication/association or connect commands");
16938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
16948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
16958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (info.offchan_tx_supported) {
16978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
16988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "off-channel TX");
16998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->capa.flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
17008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
17038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
17048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (info.p2p_supported)
17058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
17068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
17078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->capa.max_remain_on_chan = info.max_remain_on_chan;
17088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
17108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
17118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
17148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
17158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
17168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Initialize generic netlink and nl80211 */
17188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
17208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nl_cb == NULL) {
17218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
17228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "callbacks");
17238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto err1;
17248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->nl_handle = nl80211_handle_alloc(drv->nl_cb);
17278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nl_handle == NULL) {
17288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
17298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "callbacks");
17308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto err2;
17318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->nl_handle_event = nl80211_handle_alloc(drv->nl_cb);
17348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nl_handle_event == NULL) {
17358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
17368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "callbacks (event)");
17378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto err2b;
17388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (genl_connect(drv->nl_handle)) {
17418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
17428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "netlink");
17438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto err3;
17448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (genl_connect(drv->nl_handle_event)) {
17478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
17488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "netlink (event)");
17498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto err3;
17508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_LIBNL20
17538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (genl_ctrl_alloc_cache(drv->nl_handle, &drv->nl_cache) < 0) {
17548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
17558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "netlink cache");
17568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto err3;
17578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (genl_ctrl_alloc_cache(drv->nl_handle_event, &drv->nl_cache_event) <
17598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    0) {
17608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
17618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "netlink cache (event)");
17628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto err3b;
17638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* CONFIG_LIBNL20 */
17658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle);
17668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nl_cache == NULL) {
17678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
17688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "netlink cache");
17698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto err3;
17708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->nl_cache_event = genl_ctrl_alloc_cache(drv->nl_handle_event);
17728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nl_cache_event == NULL) {
17738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
17748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "netlink cache (event)");
17758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto err3b;
17768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_LIBNL20 */
17788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211");
17808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nl80211 == NULL) {
17818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
17828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "found");
17838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto err4;
17848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = nl_get_multicast_id(drv, "nl80211", "scan");
17878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret >= 0)
17888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = nl_socket_add_membership(drv->nl_handle_event, ret);
17898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
17908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
17918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "membership for scan events: %d (%s)",
17928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ret, strerror(-ret));
17938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto err4;
17948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = nl_get_multicast_id(drv, "nl80211", "mlme");
17978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret >= 0)
17988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = nl_socket_add_membership(drv->nl_handle_event, ret);
17998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
18008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
18018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "membership for mlme events: %d (%s)",
18028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ret, strerror(-ret));
18038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto err4;
18048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = nl_get_multicast_id(drv, "nl80211", "regulatory");
18078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret >= 0)
18088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = nl_socket_add_membership(drv->nl_handle_event, ret);
18098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
18108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
18118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "membership for regulatory events: %d (%s)",
18128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ret, strerror(-ret));
18138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Continue without regulatory events */
18148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_event),
18178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 wpa_driver_nl80211_event_receive, drv,
18188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 drv->nl_handle_event);
18198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
18218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidterr4:
18238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cache_free(drv->nl_cache_event);
18248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidterr3b:
18258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cache_free(drv->nl_cache);
18268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidterr3:
18278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl80211_handle_destroy(drv->nl_handle_event);
18288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidterr2b:
18298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl80211_handle_destroy(drv->nl_handle);
18308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidterr2:
18318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cb_put(drv->nl_cb);
18328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidterr1:
18338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
18348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
18358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_rfkill_blocked(void *ctx)
18388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
18398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
18408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
18418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * This may be for any interface; use ifdown event to disable
18428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * interface.
18438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
18448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
18458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_rfkill_unblocked(void *ctx)
18488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
18498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = ctx;
18508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
18518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (linux_set_iface_flags(drv->ioctl_sock, drv->first_bss.ifname, 1)) {
18528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
18538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "after rfkill unblock");
18548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
18558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* rtnetlink ifup handler will report interface as enabled */
18578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
18588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_get_phy_name(struct wpa_driver_nl80211_data *drv)
18618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
18628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Find phy (radio) to which this interface belongs */
18638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char buf[90], *pos;
18648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int f, rv;
18658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->phyname[0] = '\0';
18678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	snprintf(buf, sizeof(buf) - 1, "/sys/class/net/%s/phy80211/name",
18688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 drv->first_bss.ifname);
18698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	f = open(buf, O_RDONLY);
18708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (f < 0) {
18718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Could not open file %s: %s",
18728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   buf, strerror(errno));
18738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
18748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rv = read(f, drv->phyname, sizeof(drv->phyname) - 1);
18778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	close(f);
18788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (rv < 0) {
18798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Could not read file %s: %s",
18808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   buf, strerror(errno));
18818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
18828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->phyname[rv] = '\0';
18858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = os_strchr(drv->phyname, '\n');
18868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (pos)
18878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*pos = '\0';
18888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
18898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   drv->first_bss.ifname, drv->phyname);
18908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
18918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
18948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_driver_nl80211_init - Initialize nl80211 driver interface
18958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ctx: context to be used when calling wpa_supplicant functions,
18968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * e.g., wpa_supplicant_event()
18978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ifname: interface name, e.g., wlan0
18988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @global_priv: private driver global data from global_init()
18998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Pointer to private data, %NULL on failure
19008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
19018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
19028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      void *global_priv)
19038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
19048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv;
19058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct netlink_config *cfg;
19068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct rfkill_config *rcfg;
19078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss;
19088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv = os_zalloc(sizeof(*drv));
19108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv == NULL)
19118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
19128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->global = global_priv;
19138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->ctx = ctx;
19148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss = &drv->first_bss;
19158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss->drv = drv;
19168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
19178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->monitor_ifidx = -1;
19188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->monitor_sock = -1;
19198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->ioctl_sock = -1;
19208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_driver_nl80211_init_nl(drv)) {
19228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(drv);
19238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
19248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl80211_get_phy_name(drv);
19278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
19298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->ioctl_sock < 0) {
19308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		perror("socket(PF_INET,SOCK_DGRAM)");
19318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
19328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cfg = os_zalloc(sizeof(*cfg));
19358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cfg == NULL)
19368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
19378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cfg->ctx = drv;
19388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
19398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
19408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->netlink = netlink_init(cfg);
19418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->netlink == NULL) {
19428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(cfg);
19438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
19448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rcfg = os_zalloc(sizeof(*rcfg));
19478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (rcfg == NULL)
19488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
19498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rcfg->ctx = drv;
19508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_strlcpy(rcfg->ifname, ifname, sizeof(rcfg->ifname));
19518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rcfg->blocked_cb = wpa_driver_nl80211_rfkill_blocked;
19528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rcfg->unblocked_cb = wpa_driver_nl80211_rfkill_unblocked;
19538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->rfkill = rfkill_init(rcfg);
19548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->rfkill == NULL) {
19558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: RFKILL status not available");
19568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(rcfg);
19578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_driver_nl80211_finish_drv_init(drv))
19608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
19618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->global)
19638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dl_list_add(&drv->global->interfaces, &drv->list);
19648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return bss;
19668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfailed:
19688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rfkill_deinit(drv->rfkill);
19698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	netlink_deinit(drv->netlink);
19708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->ioctl_sock >= 0)
19718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		close(drv->ioctl_sock);
19728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genl_family_put(drv->nl80211);
19748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cache_free(drv->nl_cache);
19758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl80211_handle_destroy(drv->nl_handle);
19768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cb_put(drv->nl_cb);
19778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
19788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(drv);
19808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
19818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_register_frame(struct wpa_driver_nl80211_data *drv,
19858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  struct nl_handle *nl_handle,
19868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  u16 type, const u8 *match, size_t match_len)
19878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
19888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
19898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
19908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
19928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
19938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
19948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
19968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    NL80211_CMD_REGISTER_ACTION, 0);
19978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
19998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
20008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
20018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv(drv, nl_handle, msg, NULL, NULL);
20038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
20048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
20058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
20068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "failed (type=%u): ret=%d (%s)",
20078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   type, ret, strerror(-ret));
20088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
20098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    match, match_len);
20108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
20118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
20128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = 0;
20138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
20148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
20158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
20168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
20178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_register_action_frame(struct wpa_driver_nl80211_data *drv,
20208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 const u8 *match, size_t match_len)
20218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
20228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
20238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return nl80211_register_frame(drv, drv->nl_handle_event,
20248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      type, match, match_len);
20258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
20268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_register_action_frames(struct wpa_driver_nl80211_data *drv)
20298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
20308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
20318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* GAS Initial Request */
20328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0a", 2) < 0)
20338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
20348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* GAS Initial Response */
20358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0b", 2) < 0)
20368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
20378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* GAS Comeback Request */
20388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0c", 2) < 0)
20398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
20408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* GAS Comeback Response */
20418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0d", 2) < 0)
20428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
20438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* P2P Public Action */
20448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nl80211_register_action_frame(drv,
20458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  (u8 *) "\x04\x09\x50\x6f\x9a\x09",
20468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  6) < 0)
20478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
20488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* P2P Action */
20498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nl80211_register_action_frame(drv,
20508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  (u8 *) "\x7f\x50\x6f\x9a\x09",
20518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  5) < 0)
20528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
20538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
20548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211W
20558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* SA Query Response */
20568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nl80211_register_action_frame(drv, (u8 *) "\x08\x01", 2) < 0)
20578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
20588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
20598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* FT Action frames */
20618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nl80211_register_action_frame(drv, (u8 *) "\x06", 1) < 0)
20628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
20638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
20648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
20658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
20668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
20688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
20698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
20728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
20738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
20748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
20758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int
20788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtwpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
20798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
20808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = &drv->first_bss;
20818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int send_rfkill_event = 0;
20828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->ifindex = if_nametoindex(bss->ifname);
20848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->first_bss.ifindex = drv->ifindex;
20858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef HOSTAPD
20878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA) < 0) {
20888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Could not configure driver to "
20898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "use managed mode");
20908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
20918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) {
20938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (rfkill_is_blocked(drv->rfkill)) {
20948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable "
20958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "interface '%s' due to rfkill",
20968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   bss->ifname);
20978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			drv->if_disabled = 1;
20988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			send_rfkill_event = 1;
20998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else {
21008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "nl80211: Could not set "
21018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "interface '%s' UP", bss->ifname);
21028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
21038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
21048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
21058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	netlink_send_oper_ifla(drv->netlink, drv->ifindex,
21078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       1, IF_OPER_DORMANT);
21088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
21098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_driver_nl80211_capa(drv))
21118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
21128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, drv->addr))
21148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
21158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nl80211_register_action_frames(drv) < 0) {
21178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
21188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "frame processing - ignore for now");
21198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
21208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Older kernel versions did not support this, so ignore the
21218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * error for now. Some functionality may not be available
21228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * because of this.
21238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
21248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
21258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (send_rfkill_event) {
21278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
21288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       drv, drv->ctx);
21298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
21308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
21328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
21338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_del_beacon(struct wpa_driver_nl80211_data *drv)
21368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
21378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
21388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
21408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
21418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
21428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
21448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_DEL_BEACON, 0);
21458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
21468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
21488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
21498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
21508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
21518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
21548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
21558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @priv: Pointer to private nl80211 data from wpa_driver_nl80211_init()
21568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
21578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Shut down driver interface and processing of driver events. Free
21588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * private data buffer if one was allocated in wpa_driver_nl80211_init().
21598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
21608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_deinit(void *priv)
21618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
21628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
21638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
21648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nl_handle_preq)
21668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_driver_nl80211_probe_req_report(bss, 0);
21678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss->added_if_into_bridge) {
21688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (linux_br_del_if(drv->ioctl_sock, bss->brname, bss->ifname)
21698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    < 0)
21708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
21718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "interface %s from bridge %s: %s",
21728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   bss->ifname, bss->brname, strerror(errno));
21738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
21748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss->added_bridge) {
21758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (linux_br_del(drv->ioctl_sock, bss->brname) < 0)
21768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
21778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "bridge %s: %s",
21788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   bss->brname, strerror(errno));
21798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
21808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl80211_remove_monitor_interface(drv);
21828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nlmode == NL80211_IFTYPE_AP)
21848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_driver_nl80211_del_beacon(drv);
21858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
21878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->last_freq_ht) {
21888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Clear HT flags from the driver */
21898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct hostapd_freq_params freq;
21908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memset(&freq, 0, sizeof(freq));
21918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		freq.freq = drv->last_freq;
21928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		i802_set_freq(priv, &freq);
21938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
21948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->eapol_sock >= 0) {
21968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_unregister_read_sock(drv->eapol_sock);
21978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		close(drv->eapol_sock);
21988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
21998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->if_indices != drv->default_if_indices)
22018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(drv->if_indices);
22028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
22038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->disable_11b_rates)
22058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_disable_11b_rates(drv, drv->ifindex, 0);
22068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
22088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	netlink_deinit(drv->netlink);
22098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rfkill_deinit(drv->rfkill);
22108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
22128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	(void) linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0);
22148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA);
22158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->ioctl_sock >= 0)
22178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		close(drv->ioctl_sock);
22188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
22208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genl_family_put(drv->nl80211);
22218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cache_free(drv->nl_cache);
22228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cache_free(drv->nl_cache_event);
22238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl80211_handle_destroy(drv->nl_handle);
22248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl80211_handle_destroy(drv->nl_handle_event);
22258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cb_put(drv->nl_cb);
22268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(drv->filter_ssids);
22288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->global)
22308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		dl_list_del(&drv->list);
22318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(drv);
22338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
22348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
22378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
22388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @eloop_ctx: Driver private data
22398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
22408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
22418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function can be used as registered timeout when starting a scan to
22428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * generate a scan completed event if the driver does not report this.
22438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
22448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
22458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
22468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = eloop_ctx;
22478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->ap_scan_as_station) {
22488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_driver_nl80211_set_mode(&drv->first_bss,
22498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    IEEE80211_MODE_AP);
22508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->ap_scan_as_station = 0;
22518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
22528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
22538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
22548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
22558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
22588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_driver_nl80211_scan - Request the driver to initiate scan
22598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
22608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @params: Scan parameters
22618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
22628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
22638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_scan(void *priv,
22648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   struct wpa_driver_scan_params *params)
22658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
22668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
22678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
22688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = 0, timeout;
22698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg, *ssids, *freqs;
22708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
22718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
22738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ssids = nlmsg_alloc();
22748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	freqs = nlmsg_alloc();
22758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg || !ssids || !freqs) {
22768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nlmsg_free(msg);
22778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nlmsg_free(ssids);
22788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nlmsg_free(freqs);
22798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
22808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
22818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(drv->filter_ssids);
22838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->filter_ssids = params->filter_ssids;
22848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	params->filter_ssids = NULL;
22858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->num_filter_ssids = params->num_filter_ssids;
22868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
22888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    NL80211_CMD_TRIGGER_SCAN, 0);
22898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
22918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
22928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < params->num_ssids; i++) {
22938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan SSID",
22948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  params->ssids[i].ssid,
22958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  params->ssids[i].ssid_len);
22968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len,
22978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->ssids[i].ssid);
22988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
22998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->num_ssids)
23008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
23018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->extra_ies) {
23038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan extra IEs",
23048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  params->extra_ies, params->extra_ies_len);
23058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
23068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->extra_ies);
23078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
23088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->freqs) {
23108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (i = 0; params->freqs[i]; i++) {
23118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
23128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "MHz", params->freqs[i]);
23138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
23148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
23158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
23168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
23178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
23198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
23208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
23218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
23228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", ret, strerror(-ret));
23238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
23248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (drv->nlmode == NL80211_IFTYPE_AP) {
23258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/*
23268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * mac80211 does not allow scan requests in AP mode, so
23278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * try to do this in station mode.
23288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 */
23298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (wpa_driver_nl80211_set_mode(bss,
23308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt							IEEE80211_MODE_INFRA))
23318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				goto nla_put_failure;
23328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (wpa_driver_nl80211_scan(drv, params)) {
23348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_driver_nl80211_set_mode(bss,
23358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt							    IEEE80211_MODE_AP);
23368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				goto nla_put_failure;
23378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
23388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* Restore AP mode when processing scan results */
23408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			drv->ap_scan_as_station = 1;
23418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ret = 0;
23428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else
23438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto nla_put_failure;
23448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* HOSTAPD */
23458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
23468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
23478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
23488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Not all drivers generate "scan completed" wireless event, so try to
23508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * read results after a timeout. */
23518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	timeout = 10;
23528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->scan_complete_events) {
23538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
23548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * The driver seems to deliver events to notify when scan is
23558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * complete, so use longer timeout to avoid race conditions
23568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * with scanning and following association request.
23578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
23588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		timeout = 30;
23598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
23608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
23618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "seconds", ret, timeout);
23628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
23638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
23648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       drv, drv->ctx);
23658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
23678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(ssids);
23688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
23698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(freqs);
23708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
23718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
23728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
23758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
23768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *end, *pos;
23778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ies == NULL)
23798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
23808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = ies;
23828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = ies + ies_len;
23838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (pos + 1 < end) {
23858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos + 2 + pos[1] > end)
23868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
23878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (pos[0] == ie)
23888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return pos;
23898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2 + pos[1];
23908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
23918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
23938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
23948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
23968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
23978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 const u8 *ie, size_t ie_len)
23988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
23998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *ssid;
24008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
24018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->filter_ssids == NULL)
24038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
24048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID);
24068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ssid == NULL)
24078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 1;
24088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < drv->num_filter_ssids; i++) {
24108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ssid[1] == drv->filter_ssids[i].ssid_len &&
24118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) ==
24128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0)
24138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 0;
24148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
24158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 1;
24178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
24188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int bss_info_handler(struct nl_msg *msg, void *arg)
24218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
24228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
24238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
24248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *bss[NL80211_BSS_MAX + 1];
24258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
24268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
24278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
24288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_TSF] = { .type = NLA_U64 },
24298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
24308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
24318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
24328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
24338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
24348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_STATUS] = { .type = NLA_U32 },
24358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
24368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
24378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
24388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl80211_bss_info_arg *_arg = arg;
24398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_results *res = _arg->res;
24408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_res **tmp;
24418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_res *r;
24428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *ie, *beacon_ie;
24438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t ie_len, beacon_ie_len;
24448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *pos;
244587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	size_t i;
24468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
24488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
24498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!tb[NL80211_ATTR_BSS])
24508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
24518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
24528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     bss_policy))
24538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
245487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	if (bss[NL80211_BSS_STATUS]) {
245587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		enum nl80211_bss_status status;
245687fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		status = nla_get_u32(bss[NL80211_BSS_STATUS]);
245787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		if (status == NL80211_BSS_STATUS_ASSOCIATED &&
245887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		    bss[NL80211_BSS_FREQUENCY]) {
245987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen			_arg->assoc_freq =
246087fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen				nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
246187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen			wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
246287fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen				   _arg->assoc_freq);
246387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		}
246487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	}
246587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	if (!res)
246687fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		return NL_SKIP;
24678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
24688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
24698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
24708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
24718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ie = NULL;
24728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ie_len = 0;
24738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
24748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss[NL80211_BSS_BEACON_IES]) {
24758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]);
24768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]);
24778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
24788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		beacon_ie = NULL;
24798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		beacon_ie_len = 0;
24808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
24818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
24838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  ie ? ie_len : beacon_ie_len))
24848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
24858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
24868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
24878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (r == NULL)
24888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
24898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss[NL80211_BSS_BSSID])
24908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
24918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  ETH_ALEN);
24928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss[NL80211_BSS_FREQUENCY])
24938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
24948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss[NL80211_BSS_BEACON_INTERVAL])
24958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
24968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss[NL80211_BSS_CAPABILITY])
24978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
24988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	r->flags |= WPA_SCAN_NOISE_INVALID;
24998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss[NL80211_BSS_SIGNAL_MBM]) {
25008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
25018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->level /= 100; /* mBm to dBm */
25028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
25038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
25048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
25058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->flags |= WPA_SCAN_LEVEL_INVALID;
25068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else
25078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
25088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss[NL80211_BSS_TSF])
25098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
25108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss[NL80211_BSS_SEEN_MS_AGO])
25118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
25128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	r->ie_len = ie_len;
25138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = (u8 *) (r + 1);
25148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ie) {
25158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(pos, ie, ie_len);
25168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += ie_len;
25178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
25188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	r->beacon_ie_len = beacon_ie_len;
25198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (beacon_ie)
25208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(pos, beacon_ie, beacon_ie_len);
25218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss[NL80211_BSS_STATUS]) {
25238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		enum nl80211_bss_status status;
25248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		status = nla_get_u32(bss[NL80211_BSS_STATUS]);
25258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (status) {
25268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case NL80211_BSS_STATUS_AUTHENTICATED:
25278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			r->flags |= WPA_SCAN_AUTHENTICATED;
25288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
25298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case NL80211_BSS_STATUS_ASSOCIATED:
25308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			r->flags |= WPA_SCAN_ASSOCIATED;
25318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
25328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
25338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
25348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
25358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
25368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
253787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	/*
253887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	 * cfg80211 maintains separate BSS table entries for APs if the same
253987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	 * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
254087fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	 * not use frequency as a separate key in the BSS table, so filter out
254187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	 * duplicated entries. Prefer associated BSS entry in such a case in
254287fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	 * order to get the correct frequency into the BSS table.
254387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	 */
254487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	for (i = 0; i < res->num; i++) {
254587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		const u8 *s1, *s2;
254687fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0)
254787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen			continue;
254887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
254987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		s1 = nl80211_get_ie((u8 *) (res->res[i] + 1),
255087fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen				    res->res[i]->ie_len, WLAN_EID_SSID);
255187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		s2 = nl80211_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
255287fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
255387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		    os_memcmp(s1, s2, 2 + s1[1]) != 0)
255487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen			continue;
255587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
255687fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		/* Same BSSID,SSID was already included in scan results */
255787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
255887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen			   "for " MACSTR, MAC2STR(r->bssid));
255987fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
256087fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		if ((r->flags & WPA_SCAN_ASSOCIATED) &&
256187fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		    !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) {
256287fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen			os_free(res->res[i]);
256387fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen			res->res[i] = r;
256487fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		} else
256587fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen			os_free(r);
256687fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen		return NL_SKIP;
256787fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen	}
256887fd279308af3f806848c8f2ab65ef18c6ac4c30Jouni Malinen
25698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tmp = os_realloc(res->res,
25708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 (res->num + 1) * sizeof(struct wpa_scan_res *));
25718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tmp == NULL) {
25728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(r);
25738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
25748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
25758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	tmp[res->num++] = r;
25768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res->res = tmp;
25778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
25798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
25808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void clear_state_mismatch(struct wpa_driver_nl80211_data *drv,
25838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 const u8 *addr)
25848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
25858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
25868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Clear possible state "
25878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "mismatch (" MACSTR ")", MAC2STR(addr));
25888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_driver_nl80211_mlme(drv, addr,
25898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					NL80211_CMD_DEAUTHENTICATE,
25908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					WLAN_REASON_PREV_AUTH_NOT_VALID, 1);
25918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
25928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
25938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
25958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_check_bss_status(
25968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res)
25978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
25988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
25998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < res->num; i++) {
26018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wpa_scan_res *r = res->res[i];
26028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (r->flags & WPA_SCAN_AUTHENTICATED) {
26038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Scan results "
26048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "indicates BSS status with " MACSTR
26058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   " as authenticated",
26068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   MAC2STR(r->bssid));
26078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (drv->nlmode == NL80211_IFTYPE_STATION &&
26088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 &&
26098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) !=
26108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    0) {
26118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "nl80211: Unknown BSSID"
26128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   " in local state (auth=" MACSTR
26138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   " assoc=" MACSTR ")",
26148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   MAC2STR(drv->auth_bssid),
26158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   MAC2STR(drv->bssid));
26168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				clear_state_mismatch(drv, r->bssid);
26178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
26188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
26198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (r->flags & WPA_SCAN_ASSOCIATED) {
26218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Scan results "
26228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "indicate BSS status with " MACSTR
26238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   " as associated",
26248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   MAC2STR(r->bssid));
26258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (drv->nlmode == NL80211_IFTYPE_STATION &&
26268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    !drv->associated) {
26278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "nl80211: Local state "
26288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "(not associated) does not match "
26298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "with BSS state");
26308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				clear_state_mismatch(drv, r->bssid);
26318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			} else if (drv->nlmode == NL80211_IFTYPE_STATION &&
26328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
26338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   0) {
26348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				wpa_printf(MSG_DEBUG, "nl80211: Local state "
26358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "(associated with " MACSTR ") does "
26368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   "not match with BSS state",
26378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   MAC2STR(drv->bssid));
26388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				clear_state_mismatch(drv, r->bssid);
26398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				clear_state_mismatch(drv, drv->bssid);
26408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
26418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
26428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
26438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
26448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_scan_results_free(struct wpa_scan_results *res)
26478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
26488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
26498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res == NULL)
26518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
26528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < res->num; i++)
26548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(res->res[i]);
26558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(res->res);
26568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(res);
26578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
26588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpa_scan_results *
26618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
26628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
26638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
26648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_results *res;
26658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
26668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl80211_bss_info_arg arg;
26678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = os_zalloc(sizeof(*res));
26698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res == NULL)
26708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
26718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
26728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
26738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
26748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, NLM_F_DUMP,
26768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    NL80211_CMD_GET_SCAN, 0);
26778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
26788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	arg.drv = drv;
26808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	arg.res = res;
26818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
26828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
26838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == 0) {
26848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Received scan results (%lu BSSes)",
26858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (unsigned long) res->num);
26868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return res;
26878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
26888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
26898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "(%s)", ret, strerror(-ret));
26908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
26918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
26928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_scan_results_free(res);
26938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
26948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
26958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
26988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
26998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
27008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Scan results on success, -1 on failure
27018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
27028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpa_scan_results *
27038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtwpa_driver_nl80211_get_scan_results(void *priv)
27048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
27058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
27068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
27078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_results *res;
27088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = nl80211_get_scan_results(drv);
27108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res)
27118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_driver_nl80211_check_bss_status(drv, res);
27128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return res;
27138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
27148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
27178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
27188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_scan_results *res;
27198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
27208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = nl80211_get_scan_results(drv);
27228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res == NULL) {
27238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
27248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
27258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
27268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
27288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < res->num; i++) {
27298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wpa_scan_res *r = res->res[i];
27308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s%s",
27318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (int) i, (int) res->num, MAC2STR(r->bssid),
27328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   r->flags & WPA_SCAN_AUTHENTICATED ? " [auth]" : "",
27338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
27348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
27358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_scan_results_free(res);
27378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
27388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_set_key(const char *ifname, void *priv,
27418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      enum wpa_alg alg, const u8 *addr,
27428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      int key_idx, int set_tx,
27438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      const u8 *seq, size_t seq_len,
27448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      const u8 *key, size_t key_len)
27458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
27468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
27478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
27488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifindex = if_nametoindex(ifname);
27498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
27508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
27518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s: ifindex=%d alg=%d addr=%p key_idx=%d "
27538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "set_tx=%d seq_len=%lu key_len=%lu",
27548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   __func__, ifindex, alg, addr, key_idx, set_tx,
27558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (unsigned long) seq_len, (unsigned long) key_len);
27568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
27588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
27598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
27608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (alg == WPA_ALG_NONE) {
27628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
27638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    0, NL80211_CMD_DEL_KEY, 0);
27648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
27658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
27668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    0, NL80211_CMD_NEW_KEY, 0);
27678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
27688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (alg) {
27698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case WPA_ALG_WEP:
27708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (key_len == 5)
27718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
27728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    WLAN_CIPHER_SUITE_WEP40);
27738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else
27748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
27758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    WLAN_CIPHER_SUITE_WEP104);
27768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
27778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case WPA_ALG_TKIP:
27788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
27798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    WLAN_CIPHER_SUITE_TKIP);
27808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
27818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case WPA_ALG_CCMP:
27828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
27838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    WLAN_CIPHER_SUITE_CCMP);
27848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
27858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case WPA_ALG_IGTK:
27868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
27878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    WLAN_CIPHER_SUITE_AES_CMAC);
27888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
27898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
27908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
27918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "algorithm %d", __func__, alg);
27928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nlmsg_free(msg);
27938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
27948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
27958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
27968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
27978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (seq && seq_len)
27988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq);
27998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (addr && !is_broadcast_ether_addr(addr)) {
28018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "   addr=" MACSTR, MAC2STR(addr));
28028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
28038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (alg != WPA_ALG_WEP && key_idx && !set_tx) {
28058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "   RSN IBSS RX GTK");
28068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE,
28078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    NL80211_KEYTYPE_GROUP);
28088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
28098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (addr && is_broadcast_ether_addr(addr)) {
28108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct nl_msg *types;
28118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int err;
28128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "   broadcast key");
28138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		types = nlmsg_alloc();
28148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!types)
28158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto nla_put_failure;
28168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
28178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
28188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     types);
28198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nlmsg_free(types);
28208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (err)
28218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto nla_put_failure;
28228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
28238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
28248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
28258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
28278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
28288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = 0;
28298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret)
28308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d %s)",
28318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ret, strerror(-ret));
28328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
28348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * If we failed or don't need to set the default TX key (below),
28358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * we're done here.
28368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
28378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret || !set_tx || alg == WPA_ALG_NONE)
28388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ret;
28398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nlmode == NL80211_IFTYPE_AP && addr &&
28408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    !is_broadcast_ether_addr(addr))
28418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ret;
28428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
28448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
28458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
28468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
28488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_SET_KEY, 0);
28498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
28508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
28518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (alg == WPA_ALG_IGTK)
28528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT);
28538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
28548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
28558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (addr && is_broadcast_ether_addr(addr)) {
28568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct nl_msg *types;
28578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int err;
28588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		types = nlmsg_alloc();
28598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!types)
28608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto nla_put_failure;
28618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
28628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
28638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     types);
28648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nlmsg_free(types);
28658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (err)
28668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto nla_put_failure;
28678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (addr) {
28688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct nl_msg *types;
28698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int err;
28708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		types = nlmsg_alloc();
28718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!types)
28728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto nla_put_failure;
28738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_FLAG(types, NL80211_KEY_DEFAULT_TYPE_UNICAST);
28748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		err = nla_put_nested(msg, NL80211_ATTR_KEY_DEFAULT_TYPES,
28758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     types);
28768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nlmsg_free(types);
28778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (err)
28788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto nla_put_failure;
28798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
28808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
28828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == -ENOENT)
28838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = 0;
28848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret)
28858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: set_key default failed; "
28868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "err=%d %s)", ret, strerror(-ret));
28878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
28888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
28908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
28918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
28928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
28948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
28958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      int key_idx, int defkey,
28968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      const u8 *seq, size_t seq_len,
28978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      const u8 *key, size_t key_len)
28988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
28998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY);
29008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!key_attr)
29018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
29028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (defkey && alg == WPA_ALG_IGTK)
29048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_MGMT);
29058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (defkey)
29068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
29078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx);
29098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (alg) {
29118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_ALG_WEP:
29128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (key_len == 5)
29138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
29148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    WLAN_CIPHER_SUITE_WEP40);
29158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else
29168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
29178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    WLAN_CIPHER_SUITE_WEP104);
29188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
29198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_ALG_TKIP:
29208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_TKIP);
29218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
29228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_ALG_CCMP:
29238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_KEY_CIPHER, WLAN_CIPHER_SUITE_CCMP);
29248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
29258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_ALG_IGTK:
29268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
29278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    WLAN_CIPHER_SUITE_AES_CMAC);
29288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
29298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
29308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
29318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "algorithm %d", __func__, alg);
29328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
29338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
29348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (seq && seq_len)
29368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_KEY_SEQ, seq_len, seq);
29378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_KEY_DATA, key_len, key);
29398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_nest_end(msg, key_attr);
29418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
29438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
29448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
29458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
29468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_set_conn_keys(struct wpa_driver_associate_params *params,
29498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 struct nl_msg *msg)
29508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
29518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i, privacy = 0;
29528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *nl_keys, *nl_key;
29538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < 4; i++) {
29558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!params->wep_key[i])
29568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
29578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		privacy = 1;
29588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
29598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
29608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->wps == WPS_MODE_PRIVACY)
29618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		privacy = 1;
29628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->pairwise_suite &&
29638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    params->pairwise_suite != WPA_CIPHER_NONE)
29648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		privacy = 1;
29658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!privacy)
29678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
29688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
29708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
29728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!nl_keys)
29738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
29748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < 4; i++) {
29768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!params->wep_key[i])
29778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
29788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl_key = nla_nest_start(msg, i);
29808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!nl_key)
29818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto nla_put_failure;
29828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_KEY_DATA, params->wep_key_len[i],
29848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->wep_key[i]);
29858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->wep_key_len[i] == 5)
29868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
29878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    WLAN_CIPHER_SUITE_WEP40);
29888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else
29898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
29908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    WLAN_CIPHER_SUITE_WEP104);
29918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U8(msg, NL80211_KEY_IDX, i);
29938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (i == params->wep_tx_keyidx)
29958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
29968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
29978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_nest_end(msg, nl_key);
29988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
29998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_nest_end(msg, nl_keys);
30008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
30028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
30048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
30058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
30068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
30098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   const u8 *addr, int cmd, u16 reason_code,
30108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   int local_state_change)
30118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
30128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
30138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
30148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
30168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
30178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
30188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, cmd, 0);
30208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
30228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code);
30238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
30248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (local_state_change)
30258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
30268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
30288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
30298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
30308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
30318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", ret, strerror(-ret));
30328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
30338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
30348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = 0;
30358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
30378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
30388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
30398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
30408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
30438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 const u8 *addr, int reason_code)
30448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
30458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
30468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   __func__, MAC2STR(addr), reason_code);
30478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->associated = 0;
30488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISCONNECT,
30498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       reason_code, 0);
30508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
30518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
30548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     int reason_code)
30558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
30568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
30578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
30588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
30598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
30608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
30618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   __func__, MAC2STR(addr), reason_code);
30628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->associated = 0;
30638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nlmode == NL80211_IFTYPE_ADHOC)
30648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return nl80211_leave_ibss(drv);
30658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
30668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       reason_code, 0);
30678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
30688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
30718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   int reason_code)
30728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
30738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
30748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
30758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
30768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return wpa_driver_nl80211_disconnect(drv, addr, reason_code);
30778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s", __func__);
30788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->associated = 0;
30798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DISASSOCIATE,
30808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       reason_code, 0);
30818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
30828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_authenticate(
30858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *priv, struct wpa_driver_auth_params *params)
30868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
30878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
30888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
30898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1, i;
30908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
30918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum nl80211_auth_type type;
30928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int count = 0;
30938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
30948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->associated = 0;
30958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(drv->auth_bssid, 0, ETH_ALEN);
30968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* FIX: IBSS mode */
30978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nlmode != NL80211_IFTYPE_STATION &&
30988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA) < 0)
30998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
31008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtretry:
31028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
31038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
31048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
31058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
31078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   drv->ifindex);
31088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
31108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    NL80211_CMD_AUTHENTICATE, 0);
31118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < 4; i++) {
31138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!params->wep_key[i])
31148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
31158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_driver_nl80211_set_key(bss->ifname, priv, WPA_ALG_WEP,
31168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   NULL, i,
31178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   i == params->wep_tx_keyidx, NULL, 0,
31188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   params->wep_key[i],
31198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					   params->wep_key_len[i]);
31208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->wep_tx_keyidx != i)
31218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
31228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
31238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			       params->wep_key[i], params->wep_key_len[i])) {
31248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nlmsg_free(msg);
31258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
31268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
31278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
31288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
31308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->bssid) {
31318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * bssid=" MACSTR,
31328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(params->bssid));
31338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
31348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
31358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->freq) {
31368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
31378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
31388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
31398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->ssid) {
31408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
31418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  params->ssid, params->ssid_len);
31428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
31438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->ssid);
31448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
31458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "  * IEs", params->ie, params->ie_len);
31468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->ie)
31478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_IE, params->ie_len, params->ie);
31488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->auth_alg & WPA_AUTH_ALG_OPEN)
31498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		type = NL80211_AUTHTYPE_OPEN_SYSTEM;
31508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
31518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		type = NL80211_AUTHTYPE_SHARED_KEY;
31528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
31538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		type = NL80211_AUTHTYPE_NETWORK_EAP;
31548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (params->auth_alg & WPA_AUTH_ALG_FT)
31558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		type = NL80211_AUTHTYPE_FT;
31568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
31578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
31588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "  * Auth Type %d", type);
31598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
31608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->local_state_change) {
31618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * Local state change only");
31628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
31638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
31648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
31668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
31678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
31688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
31698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", ret, strerror(-ret));
31708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		count++;
31718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret == -EALREADY && count == 1 && params->bssid &&
31728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    !params->local_state_change) {
31738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/*
31748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * mac80211 does not currently accept new
31758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * authentication if we are already authenticated. As a
31768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * workaround, force deauthentication and try again.
31778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 */
31788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Retry authentication "
31798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "after forced deauthentication");
31808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_driver_nl80211_deauthenticate(
31818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				bss, params->bssid,
31828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				WLAN_REASON_PREV_AUTH_NOT_VALID);
31838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nlmsg_free(msg);
31848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto retry;
31858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
31868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
31878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
31888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = 0;
31898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Authentication request send "
31908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "successfully");
31918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
31938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
31948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
31958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
31968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
31988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct phy_info_arg {
31998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 *num_modes;
32008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_hw_modes *modes;
32018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
32028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int phy_info_handler(struct nl_msg *msg, void *arg)
32048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
32058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
32068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
32078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct phy_info_arg *phy_info = arg;
32088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
32108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
32128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
32138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
32148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
32158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
32168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
32178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
32188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
32198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
32208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
32228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
32238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
32248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG },
32258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
32268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *nl_band;
32288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *nl_freq;
32298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *nl_rate;
32308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int rem_band, rem_freq, rem_rate;
32318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_hw_modes *mode;
32328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int idx, mode_is_set;
32338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
32358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
32368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
32388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
32398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
32418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mode = os_realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode));
32428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!mode)
32438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NL_SKIP;
32448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		phy_info->modes = mode;
32458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mode_is_set = 0;
32478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mode = &phy_info->modes[*(phy_info->num_modes)];
32498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		memset(mode, 0, sizeof(*mode));
32508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*(phy_info->num_modes) += 1;
32518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
32538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  nla_len(nl_band), NULL);
32548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
32568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			mode->ht_capab = nla_get_u16(
32578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				tb_band[NL80211_BAND_ATTR_HT_CAPA]);
32588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
32598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) {
32618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			mode->a_mpdu_params |= nla_get_u8(
32628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR]) &
32638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				0x03;
32648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
32658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) {
32678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			mode->a_mpdu_params |= nla_get_u8(
32688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY]) <<
32698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				2;
32708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
32718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (tb_band[NL80211_BAND_ATTR_HT_MCS_SET] &&
32738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    nla_len(tb_band[NL80211_BAND_ATTR_HT_MCS_SET])) {
32748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			u8 *mcs;
32758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			mcs = nla_data(tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
32768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(mode->mcs_set, mcs, 16);
32778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
32788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
32808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
32818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  nla_len(nl_freq), freq_policy);
32828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
32838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				continue;
32848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			mode->num_channels++;
32858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
32868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mode->channels = os_zalloc(mode->num_channels * sizeof(struct hostapd_channel_data));
32888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!mode->channels)
32898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NL_SKIP;
32908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		idx = 0;
32928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
32948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
32958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  nla_len(nl_freq), freq_policy);
32968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
32978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				continue;
32988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
32998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
33008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			mode->channels[idx].flag = 0;
33018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (!mode_is_set) {
33038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				/* crude heuristic */
33048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				if (mode->channels[idx].freq < 4000)
33058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					mode->mode = HOSTAPD_MODE_IEEE80211B;
33068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				else
33078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					mode->mode = HOSTAPD_MODE_IEEE80211A;
33088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				mode_is_set = 1;
33098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
33108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* crude heuristic */
33128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (mode->channels[idx].freq < 4000)
33138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				if (mode->channels[idx].freq == 2484)
33148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					mode->channels[idx].chan = 14;
33158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				else
33168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					mode->channels[idx].chan = (mode->channels[idx].freq - 2407) / 5;
33178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else
33188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				mode->channels[idx].chan = mode->channels[idx].freq/5 - 1000;
33198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
33218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				mode->channels[idx].flag |=
33228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					HOSTAPD_CHAN_DISABLED;
33238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
33248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				mode->channels[idx].flag |=
33258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					HOSTAPD_CHAN_PASSIVE_SCAN;
33268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
33278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				mode->channels[idx].flag |=
33288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					HOSTAPD_CHAN_NO_IBSS;
33298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
33308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				mode->channels[idx].flag |=
33318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					HOSTAPD_CHAN_RADAR;
33328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
33348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
33358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				mode->channels[idx].max_tx_power =
33368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
33378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			idx++;
33398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
33408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
33428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
33438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  nla_len(nl_rate), rate_policy);
33448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
33458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				continue;
33468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			mode->num_rates++;
33478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
33488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mode->rates = os_zalloc(mode->num_rates * sizeof(int));
33508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!mode->rates)
33518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return NL_SKIP;
33528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		idx = 0;
33548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
33568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
33578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  nla_len(nl_rate), rate_policy);
33588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
33598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				continue;
33608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			mode->rates[idx] = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]);
33618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* crude heuristic */
33638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (mode->mode == HOSTAPD_MODE_IEEE80211B &&
33648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    mode->rates[idx] > 200)
33658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				mode->mode = HOSTAPD_MODE_IEEE80211G;
33668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			idx++;
33688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
33698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
33708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
33728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
33738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct hostapd_hw_modes *
33758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtwpa_driver_nl80211_add_11b(struct hostapd_hw_modes *modes, u16 *num_modes)
33768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
33778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 m;
33788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
33798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i, mode11g_idx = -1;
33808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* If only 802.11g mode is included, use it to construct matching
33828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * 802.11b mode data. */
33838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (m = 0; m < *num_modes; m++) {
33858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (modes[m].mode == HOSTAPD_MODE_IEEE80211B)
33868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return modes; /* 802.11b already included */
33878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (modes[m].mode == HOSTAPD_MODE_IEEE80211G)
33888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			mode11g_idx = m;
33898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
33908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (mode11g_idx < 0)
33928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return modes; /* 2.4 GHz band not supported at all */
33938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nmodes = os_realloc(modes, (*num_modes + 1) * sizeof(*nmodes));
33958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nmodes == NULL)
33968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return modes; /* Could not add 802.11b mode */
33978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
33988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mode = &nmodes[*num_modes];
33998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(mode, 0, sizeof(*mode));
34008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	(*num_modes)++;
34018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	modes = nmodes;
34028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mode->mode = HOSTAPD_MODE_IEEE80211B;
34048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mode11g = &modes[mode11g_idx];
34068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mode->num_channels = mode11g->num_channels;
34078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mode->channels = os_malloc(mode11g->num_channels *
34088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   sizeof(struct hostapd_channel_data));
34098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (mode->channels == NULL) {
34108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		(*num_modes)--;
34118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return modes; /* Could not add 802.11b mode */
34128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
34138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(mode->channels, mode11g->channels,
34148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  mode11g->num_channels * sizeof(struct hostapd_channel_data));
34158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mode->num_rates = 0;
34178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mode->rates = os_malloc(4 * sizeof(int));
34188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (mode->rates == NULL) {
34198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(mode->channels);
34208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		(*num_modes)--;
34218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return modes; /* Could not add 802.11b mode */
34228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
34238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < mode11g->num_rates; i++) {
34258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 &&
34268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    mode11g->rates[i] != 55 && mode11g->rates[i] != 110)
34278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
34288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mode->rates[mode->num_rates] = mode11g->rates[i];
34298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		mode->num_rates++;
34308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (mode->num_rates == 4)
34318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
34328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
34338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (mode->num_rates == 0) {
34358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(mode->channels);
34368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(mode->rates);
34378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		(*num_modes)--;
34388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return modes; /* No 802.11b rates */
34398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
34408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g "
34428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "information");
34438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return modes;
34458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
34468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_set_ht40_mode(struct hostapd_hw_modes *mode, int start,
34498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  int end)
34508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
34518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int c;
34528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (c = 0; c < mode->num_channels; c++) {
34548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct hostapd_channel_data *chan = &mode->channels[c];
34558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (chan->freq - 10 >= start && chan->freq + 10 <= end)
34568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			chan->flag |= HOSTAPD_CHAN_HT40;
34578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
34588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
34598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start,
34628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      int end)
34638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
34648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int c;
34658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (c = 0; c < mode->num_channels; c++) {
34678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct hostapd_channel_data *chan = &mode->channels[c];
34688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!(chan->flag & HOSTAPD_CHAN_HT40))
34698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
34708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (chan->freq - 30 >= start && chan->freq - 10 <= end)
34718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			chan->flag |= HOSTAPD_CHAN_HT40MINUS;
34728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (chan->freq + 10 >= start && chan->freq + 30 <= end)
34738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			chan->flag |= HOSTAPD_CHAN_HT40PLUS;
34748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
34758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
34768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_reg_rule_ht40(struct nlattr *tb[],
34798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  struct phy_info_arg *results)
34808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
34818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 start, end, max_bw;
34828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 m;
34838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
34858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
34868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
34878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
34888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
34908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
34918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
34928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz",
34948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   start, end, max_bw);
34958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (max_bw < 40)
34968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
34978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
34988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (m = 0; m < *results->num_modes; m++) {
34998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!(results->modes[m].ht_capab &
35008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
35018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
35028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_set_ht40_mode(&results->modes[m], start, end);
35038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
35048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
35058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_reg_rule_sec(struct nlattr *tb[],
35088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 struct phy_info_arg *results)
35098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
35108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 start, end, max_bw;
35118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 m;
35128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
35148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
35158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
35168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
35178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
35198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
35208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
35218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (max_bw < 20)
35238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
35248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (m = 0; m < *results->num_modes; m++) {
35268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!(results->modes[m].ht_capab &
35278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
35288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
35298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_set_ht40_mode_sec(&results->modes[m], start, end);
35308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
35318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
35328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_get_reg(struct nl_msg *msg, void *arg)
35358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
35368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct phy_info_arg *results = arg;
35378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
35388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
35398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *nl_rule;
35408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1];
35418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int rem_rule;
35428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
35438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
35448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
35458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
35468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
35478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
35488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
35498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
35508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
35528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
35538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!tb_msg[NL80211_ATTR_REG_ALPHA2] ||
35548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    !tb_msg[NL80211_ATTR_REG_RULES]) {
35558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: No regulatory information "
35568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "available");
35578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
35588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
35598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s",
35618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]));
35628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
35648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
35658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
35668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  nla_data(nl_rule), nla_len(nl_rule), reg_policy);
35678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_reg_rule_ht40(tb_rule, results);
35688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
35698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
35718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
35728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
35738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  nla_data(nl_rule), nla_len(nl_rule), reg_policy);
35748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_reg_rule_sec(tb_rule, results);
35758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
35768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
35788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
35798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_set_ht40_flags(struct wpa_driver_nl80211_data *drv,
35828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  struct phy_info_arg *results)
35838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
35848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
35858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
35878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
35888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
35898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
35918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_GET_REG, 0);
35928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
35938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
35948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct hostapd_hw_modes *
35978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtwpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
35988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
35998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
36008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
36018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
36028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct phy_info_arg result = {
36038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		.num_modes = num_modes,
36048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		.modes = NULL,
36058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
36068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*num_modes = 0;
36088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*flags = 0;
36098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
36118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
36128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
36138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
36158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_GET_WIPHY, 0);
36168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
36188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
36208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_set_ht40_flags(drv, &result);
36218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return wpa_driver_nl80211_add_11b(result.modes, num_modes);
36228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
36238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
36248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
36258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
36268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv,
36298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 const void *data, size_t len,
36308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 int encrypt)
36318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
36328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	__u8 rtap_hdr[] = {
36338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x00, 0x00, /* radiotap version */
36348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x0e, 0x00, /* radiotap length */
36358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
36368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
36378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x00,       /* padding */
36388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x00, 0x00, /* RX and TX flags to indicate that */
36398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		0x00, 0x00, /* this is the injected frame directly */
36408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
36418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct iovec iov[2] = {
36428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		{
36438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			.iov_base = &rtap_hdr,
36448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			.iov_len = sizeof(rtap_hdr),
36458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		},
36468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		{
36478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			.iov_base = (void *) data,
36488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			.iov_len = len,
36498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
36508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
36518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct msghdr msg = {
36528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		.msg_name = NULL,
36538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		.msg_namelen = 0,
36548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		.msg_iov = iov,
36558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		.msg_iovlen = 2,
36568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		.msg_control = NULL,
36578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		.msg_controllen = 0,
36588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		.msg_flags = 0,
36598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
36608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res;
36618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encrypt)
36638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
36648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3665c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	if (drv->monitor_sock < 0) {
3666c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: No monitor socket available "
3667c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt			   "for %s", __func__);
3668c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		return -1;
3669c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	}
3670c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt
36718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = sendmsg(drv->monitor_sock, &msg, 0);
36728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res < 0) {
36738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
36748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
36758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
36768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
36778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
36788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
36818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					size_t data_len)
36828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
36838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
36848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
36858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee80211_mgmt *mgmt;
36868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int encrypt = 1;
36878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 fc;
36888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt = (struct ieee80211_mgmt *) data;
36908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	fc = le_to_host16(mgmt->frame_control);
36918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
36928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nlmode == NL80211_IFTYPE_STATION &&
36938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
36948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
36958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
36968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * The use of last_mgmt_freq is a bit of a hack,
36978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * but it works due to the single-threaded nature
36988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * of wpa_supplicant.
36998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
37008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return nl80211_send_frame_cmd(drv, drv->last_mgmt_freq, 0,
37018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      data, data_len, NULL);
37028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
37038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
37058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
37068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
37078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Only one of the authentication frame types is encrypted.
37088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * In order for static WEP encryption to work properly (i.e.,
37098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * to not encrypt the frame), we need to tell mac80211 about
37108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * the frames that must not be encrypted.
37118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
37128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
37138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction);
37148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
37158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			encrypt = 0;
37168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
37178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt);
37198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
37208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_set_beacon(void *priv,
37238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 const u8 *head, size_t head_len,
37248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 const u8 *tail, size_t tail_len,
37258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					 int dtim_period, int beacon_int)
37268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
37278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
37288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
37298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
37308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 cmd = NL80211_CMD_NEW_BEACON;
37318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
37328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int beacon_set;
37338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifindex = if_nametoindex(bss->ifname);
37348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	beacon_set = bss->beacon_set;
37368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
37388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
37398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
37408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
37428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   beacon_set);
37438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (beacon_set)
37448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cmd = NL80211_CMD_SET_BEACON;
37458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
37478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, cmd, 0);
37488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, head_len, head);
37498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail);
37508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
37518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, beacon_int);
37528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
37538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
37558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
37568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
37578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ret, strerror(-ret));
37588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
37598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->beacon_set = 1;
37608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
37618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
37628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
37638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
37648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
37658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv,
37688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       int freq, int ht_enabled,
37698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       int sec_channel_offset)
37708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
37718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
37728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
37738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
37758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
37768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
37778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
37798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    NL80211_CMD_SET_WIPHY, 0);
37808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
37818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
37828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
37838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ht_enabled) {
37848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (sec_channel_offset) {
37858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case -1:
37868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
37878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    NL80211_CHAN_HT40MINUS);
37888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
37898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case 1:
37908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
37918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    NL80211_CHAN_HT40PLUS);
37928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
37938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
37948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
37958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    NL80211_CHAN_HT20);
37968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
37978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
37988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
37998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
38018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == 0)
38028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
38038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
38048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "%d (%s)", freq, ret, strerror(-ret));
38058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
38068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
38078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
38088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_sta_add(void *priv,
38118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      struct hostapd_sta_add_params *params)
38128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
38138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
38148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
38158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
38168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -ENOBUFS;
38178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
38198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
38208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
38218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
38238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_NEW_STATION, 0);
38248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
38268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
38278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
38288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
38298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		params->supp_rates);
38308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
38318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    params->listen_interval);
38328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->ht_capabilities) {
38338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
38348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			sizeof(*params->ht_capabilities),
38358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->ht_capabilities);
38368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
38378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
38398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret)
38408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_NEW_STATION "
38418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "result: %d (%s)", ret, strerror(-ret));
38428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == -EEXIST)
38438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = 0;
38448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
38458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
38468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
38478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_sta_remove(void *priv, const u8 *addr)
38508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
38518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
38528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
38538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
38548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
38558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
38578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
38588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
38598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
38618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_DEL_STATION, 0);
38628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
38648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    if_nametoindex(bss->ifname));
38658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
38668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
38688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == -ENOENT)
38698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
38708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
38718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
38728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
38738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
38748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
38778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 int ifidx)
38788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
38798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
38808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
38828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
38848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* stop listening for EAPOL on this interface */
38858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	del_ifidx(drv, ifidx);
38868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
38878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
38898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
38908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
38918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
38938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_DEL_INTERFACE, 0);
38948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
38958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
38968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
38978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
38988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
38998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
39008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
39018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
39048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     const char *ifname,
39058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     enum nl80211_iftype iftype,
39068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     const u8 *addr, int wds)
39078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
39088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg, *flags = NULL;
39098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifidx;
39108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -ENOBUFS;
39118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
39138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
39148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
39158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
39178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_NEW_INTERFACE, 0);
39188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
39198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
39208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
39218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (iftype == NL80211_IFTYPE_MONITOR) {
39238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int err;
39248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		flags = nlmsg_alloc();
39268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!flags)
39278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto nla_put_failure;
39288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES);
39308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
39328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nlmsg_free(flags);
39348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (err)
39368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto nla_put_failure;
39378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (wds) {
39388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
39398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
39408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
39428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
39438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
39448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
39458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ifname, ret, strerror(-ret));
39468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ret;
39478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
39488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ifidx = if_nametoindex(ifname);
39508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: New interface %s created: ifindex=%d",
39518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   ifname, ifidx);
39528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ifidx <= 0)
39548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
39558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
39578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* start listening for EAPOL on this interface */
39588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	add_ifidx(drv, ifidx);
39598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
39608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (addr && iftype != NL80211_IFTYPE_MONITOR &&
39628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    linux_set_ifhwaddr(drv->ioctl_sock, ifname, addr)) {
39638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_remove_iface(drv, ifidx);
39648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
39658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
39668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ifidx;
39688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
39698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
39728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				const char *ifname, enum nl80211_iftype iftype,
39738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				const u8 *addr, int wds)
39748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
39758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
39768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
39788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* if error occured and interface exists already */
39808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == -ENFILE && if_nametoindex(ifname)) {
39818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
39828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Try to remove the interface that was already there. */
39848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_remove_iface(drv, if_nametoindex(ifname));
39858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Try to create the interface again */
39878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = nl80211_create_iface_once(drv, ifname, iftype, addr,
39888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						wds);
39898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
39908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret >= 0 && drv->disable_11b_rates)
39928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_disable_11b_rates(drv, ret, 1);
39938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
39958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
39968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
39988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
39998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
40008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee80211_hdr *hdr;
40018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 fc;
40028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
40038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = (struct ieee80211_hdr *) buf;
40058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	fc = le_to_host16(hdr->frame_control);
40068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
40088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.type = WLAN_FC_GET_TYPE(fc);
40098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
40108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.dst = hdr->addr1;
40118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.data = buf;
40128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.data_len = len;
40138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.tx_status.ack = ok;
40148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event);
40158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
40168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
40198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     u8 *buf, size_t len)
40208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
40218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
40228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&event, 0, sizeof(event));
40238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.rx_from_unknown.frame = buf;
40248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	event.rx_from_unknown.len = len;
40258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
40268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
40278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void handle_frame(struct wpa_driver_nl80211_data *drv,
40308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 u8 *buf, size_t len, int datarate, int ssi_signal)
40318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
40328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee80211_hdr *hdr;
40338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 fc;
40348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	union wpa_event_data event;
40358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = (struct ieee80211_hdr *) buf;
40378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	fc = le_to_host16(hdr->frame_control);
40388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (WLAN_FC_GET_TYPE(fc)) {
40408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WLAN_FC_TYPE_MGMT:
40418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memset(&event, 0, sizeof(event));
40428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_mgmt.frame = buf;
40438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_mgmt.frame_len = len;
40448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_mgmt.datarate = datarate;
40458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		event.rx_mgmt.ssi_signal = ssi_signal;
40468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
40478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
40488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WLAN_FC_TYPE_CTRL:
40498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* can only get here with PS-Poll frames */
40508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "CTRL");
40518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		from_unknown_sta(drv, buf, len);
40528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
40538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WLAN_FC_TYPE_DATA:
40548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		from_unknown_sta(drv, buf, len);
40558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
40568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
40578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
40588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
40618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
40628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = eloop_ctx;
40638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int len;
40648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned char buf[3000];
40658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee80211_radiotap_iterator iter;
40668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
40678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int datarate = 0, ssi_signal = 0;
40688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int injected = 0, failed = 0, rxflags = 0;
40698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len = recv(sock, buf, sizeof(buf), 0);
40718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len < 0) {
40728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		perror("recv");
40738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
40748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
40758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) {
40778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		printf("received invalid radiotap frame\n");
40788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
40798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
40808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
40818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (1) {
40828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = ieee80211_radiotap_iterator_next(&iter);
40838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret == -ENOENT)
40848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
40858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret) {
40868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			printf("received invalid radiotap frame (%d)\n", ret);
40878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return;
40888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
40898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (iter.this_arg_index) {
40908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IEEE80211_RADIOTAP_FLAGS:
40918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
40928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				len -= 4;
40938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
40948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IEEE80211_RADIOTAP_RX_FLAGS:
40958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			rxflags = 1;
40968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
40978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IEEE80211_RADIOTAP_TX_FLAGS:
40988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			injected = 1;
40998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			failed = le_to_host16((*(uint16_t *) iter.this_arg)) &
41008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					IEEE80211_RADIOTAP_F_TX_FAIL;
41018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
41028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IEEE80211_RADIOTAP_DATA_RETRIES:
41038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
41048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IEEE80211_RADIOTAP_CHANNEL:
41058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* TODO: convert from freq/flags to channel number */
41068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
41078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IEEE80211_RADIOTAP_RATE:
41088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			datarate = *iter.this_arg * 5;
41098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
41108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
41118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ssi_signal = *iter.this_arg;
41128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
41138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
41148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
41158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (rxflags && injected)
41178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
41188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!injected)
41208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		handle_frame(drv, buf + iter.max_length,
41218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     len - iter.max_length, datarate, ssi_signal);
41228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
41238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		handle_tx_callback(drv->ctx, buf + iter.max_length,
41248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   len - iter.max_length, !failed);
41258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
41268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
41298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * we post-process the filter code later and rewrite
41308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * this to the offset to the last instruction
41318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
41328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define PASS	0xFF
41338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define FAIL	0xFE
41348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct sock_filter msock_filter_insns[] = {
41368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
41378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * do a little-endian load of the radiotap length field
41388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
41398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* load lower byte into A */
41408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_B | BPF_ABS, 2),
41418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* put it into X (== index register) */
41428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_MISC| BPF_TAX, 0),
41438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* load upper byte into A */
41448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_B | BPF_ABS, 3),
41458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* left-shift it by 8 */
41468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8),
41478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* or with X */
41488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0),
41498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* put result into X */
41508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_MISC| BPF_TAX, 0),
41518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
41538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Allow management frames through, this also gives us those
41548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * management frames that we sent ourselves with status
41558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
41568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* load the lower byte of the IEEE 802.11 frame control field */
41578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_B | BPF_IND, 0),
41588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* mask off frame type and version */
41598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF),
41608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* accept frame if it's both 0, fall through otherwise */
41618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0),
41628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
41648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * TODO: add a bit to radiotap RX flags that indicates
41658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * that the sending station is not associated, then
41668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * add a filter here that filters on our DA and that flag
41678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * to allow us to deauth frames to that bad station.
41688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 *
41698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * For now allow all To DS data frames through.
41708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
41718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* load the IEEE 802.11 frame control field */
41728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_H | BPF_IND, 0),
41738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* mask off frame type, version and DS status */
41748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03),
41758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* accept frame if version 0, type 2 and To DS, fall through otherwise
41768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
41778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0),
41788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if 0
41808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
41818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * drop non-data frames
41828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
41838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* load the lower byte of the frame control field */
41848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 0),
41858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* mask off QoS bit */
41868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x0c),
41878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* drop non-data frames */
41888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_JUMP(BPF_JMP  | BPF_JEQ | BPF_K, 8, 0, FAIL),
41898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
41908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* load the upper byte of the frame control field */
41918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 1),
41928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* mask off toDS/fromDS */
41938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x03),
41948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* accept WDS frames */
41958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_JUMP(BPF_JMP  | BPF_JEQ | BPF_K, 3, PASS, 0),
41968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
41978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
41988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * add header length to index
41998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
42008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* load the lower byte of the frame control field */
42018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 0),
42028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* mask off QoS bit */
42038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x80),
42048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* right shift it by 6 to give 0 or 2 */
42058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_ALU  | BPF_RSH | BPF_K, 6),
42068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* add data frame header length */
42078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_ALU  | BPF_ADD | BPF_K, 24),
42088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* add index, was start of 802.11 header */
42098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_ALU  | BPF_ADD | BPF_X, 0),
42108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* move to index, now start of LL header */
42118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_MISC | BPF_TAX, 0),
42128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
42148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Accept empty data frames, we use those for
42158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * polling activity.
42168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
42178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_W | BPF_LEN, 0),
42188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0),
42198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
42218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Accept EAPOL frames
42228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
42238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_W | BPF_IND, 0),
42248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL),
42258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_LD  | BPF_W | BPF_IND, 4),
42268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL),
42278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* keep these last two statements or change the code below */
42298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* return 0 == "DROP" */
42308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_RET | BPF_K, 0),
42318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* return ~0 == "keep all" */
42328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	BPF_STMT(BPF_RET | BPF_K, ~0),
42338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
42348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct sock_fprog msock_filter = {
42368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.len = sizeof(msock_filter_insns)/sizeof(msock_filter_insns[0]),
42378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.filter = msock_filter_insns,
42388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
42398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int add_monitor_filter(int s)
42428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
42438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int idx;
42448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* rewrite all PASS/FAIL jump offsets */
42468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (idx = 0; idx < msock_filter.len; idx++) {
42478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct sock_filter *insn = &msock_filter_insns[idx];
42488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (BPF_CLASS(insn->code) == BPF_JMP) {
42508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (insn->code == (BPF_JMP|BPF_JA)) {
42518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				if (insn->k == PASS)
42528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					insn->k = msock_filter.len - idx - 2;
42538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				else if (insn->k == FAIL)
42548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					insn->k = msock_filter.len - idx - 3;
42558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
42568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (insn->jt == PASS)
42588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				insn->jt = msock_filter.len - idx - 2;
42598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else if (insn->jt == FAIL)
42608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				insn->jt = msock_filter.len - idx - 3;
42618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (insn->jf == PASS)
42638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				insn->jf = msock_filter.len - idx - 2;
42648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else if (insn->jf == FAIL)
42658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				insn->jf = msock_filter.len - idx - 3;
42668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
42678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
42688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
42708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       &msock_filter, sizeof(msock_filter))) {
42718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		perror("SO_ATTACH_FILTER");
42728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
42738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
42748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
42768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
42778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_remove_monitor_interface(
42808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv)
42818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
42828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->monitor_ifidx >= 0) {
42838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_remove_iface(drv, drv->monitor_ifidx);
42848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->monitor_ifidx = -1;
42858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
42868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->monitor_sock >= 0) {
42878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_unregister_read_sock(drv->monitor_sock);
42888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		close(drv->monitor_sock);
42898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->monitor_sock = -1;
42908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
42918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
42928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
42948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int
42958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
42968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
42978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char buf[IFNAMSIZ];
42988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct sockaddr_ll ll;
42998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int optval;
43008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	socklen_t optlen;
43018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
43038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf[IFNAMSIZ - 1] = '\0';
43048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->monitor_ifidx =
43068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
43078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     0);
43088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4309c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	if (drv->monitor_ifidx == -EOPNOTSUPP) {
4310c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Driver does not support "
4311c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt			   "monitor interface type - try to run without it");
4312c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		drv->no_monitor_iface_capab = 1;
4313c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	}
4314c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt
43158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->monitor_ifidx < 0)
43168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
43178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (linux_set_iface_flags(drv->ioctl_sock, buf, 1))
43198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto error;
43208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memset(&ll, 0, sizeof(ll));
43228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ll.sll_family = AF_PACKET;
43238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ll.sll_ifindex = drv->monitor_ifidx;
43248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
43258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->monitor_sock < 0) {
43268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		perror("socket[PF_PACKET,SOCK_RAW]");
43278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto error;
43288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
43298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (add_monitor_filter(drv->monitor_sock)) {
43318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "Failed to set socket filter for monitor "
43328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "interface; do filtering in user space");
43338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* This works, but will cost in performance. */
43348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
43358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
43378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		perror("monitor socket bind");
43388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto error;
43398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
43408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	optlen = sizeof(optval);
43428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	optval = 20;
43438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (setsockopt
43448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
43458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		perror("Failed to set socket priority");
43468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto error;
43478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
43488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
43508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     drv, NULL)) {
43518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		printf("Could not register monitor read socket\n");
43528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto error;
43538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
43548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
43568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt error:
43578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl80211_remove_monitor_interface(drv);
43588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
43598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
43608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
43638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_hapd_send_eapol(
43658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *priv, const u8 *addr, const u8 *data,
43668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t data_len, int encrypt, const u8 *own_addr, u32 flags)
43678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
43688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
43698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
43708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee80211_hdr *hdr;
43718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len;
43728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *pos;
43738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res;
43748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int qos = flags & WPA_STA_WMM;
43758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
43778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data_len;
43788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = os_zalloc(len);
43798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hdr == NULL) {
43808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		printf("malloc() failed for i802_send_data(len=%lu)\n",
43818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       (unsigned long) len);
43828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
43838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
43848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr->frame_control =
43868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
43878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
43888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (encrypt)
43898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
43908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (qos) {
43918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hdr->frame_control |=
43928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
43938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
43948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
43958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
43968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
43978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
43988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = (u8 *) (hdr + 1);
43998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (qos) {
44018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* add an empty QoS header if needed */
44028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos[0] = 0;
44038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos[1] = 0;
44048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		pos += 2;
44058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
44068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
44088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += sizeof(rfc1042_header);
44098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	WPA_PUT_BE16(pos, ETH_P_PAE);
44108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += 2;
44118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(pos, data, data_len);
44128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = wpa_driver_nl80211_send_frame(drv, (u8 *) hdr, len, encrypt);
44148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res < 0) {
44158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
44168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "failed: %d (%s)",
44178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (unsigned long) len, errno, strerror(errno));
44188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
44198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(hdr);
44208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return res;
44228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
44238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic u32 sta_flags_nl80211(int flags)
44268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
44278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 f = 0;
44288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (flags & WPA_STA_AUTHORIZED)
44308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
44318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (flags & WPA_STA_WMM)
44328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		f |= BIT(NL80211_STA_FLAG_WME);
44338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (flags & WPA_STA_SHORT_PREAMBLE)
44348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
44358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (flags & WPA_STA_MFP)
44368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		f |= BIT(NL80211_STA_FLAG_MFP);
44378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return f;
44398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
44408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
44438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    int total_flags,
44448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    int flags_or, int flags_and)
44458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
44468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
44478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
44488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg, *flags = NULL;
44498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl80211_sta_flag_update upd;
44508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
44528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
44538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
44548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	flags = nlmsg_alloc();
44568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!flags) {
44578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nlmsg_free(msg);
44588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
44598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
44608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
44628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_SET_STATION, 0);
44638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
44658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    if_nametoindex(bss->ifname));
44668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
44678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
44698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Backwards compatibility version using NL80211_ATTR_STA_FLAGS. This
44708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * can be removed eventually.
44718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
44728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (total_flags & WPA_STA_AUTHORIZED)
44738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
44748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (total_flags & WPA_STA_WMM)
44768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
44778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (total_flags & WPA_STA_SHORT_PREAMBLE)
44798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
44808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (total_flags & WPA_STA_MFP)
44828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
44838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
44858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
44868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&upd, 0, sizeof(upd));
44888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	upd.mask = sta_flags_nl80211(flags_or | ~flags_and);
44898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	upd.set = sta_flags_nl80211(flags_or);
44908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
44918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(flags);
44938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
44948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
44958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
44968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(flags);
44978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
44988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
44998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
45028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 struct wpa_driver_associate_params *params)
45038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
45048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->p2p)
45058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P "
45068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "group (GO)");
45078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode) ||
45088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    wpa_driver_nl80211_set_freq(drv, params->freq, 0, 0)) {
45098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_remove_monitor_interface(drv);
45108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
45118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
45128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO: setup monitor interface (and add code somewhere to remove this
45148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * when AP mode is stopped; associate with mode != 2 or drv_deinit) */
45158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
45178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
45188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv)
45218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
45228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
45238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
45248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
45268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
45278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
45288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
45308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    NL80211_CMD_LEAVE_IBSS, 0);
45318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
45328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
45338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
45348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
45358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
45368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", ret, strerror(-ret));
45378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
45388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
45398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = 0;
45418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS request sent successfully");
45428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
45448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
45458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
45468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
45478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv,
45508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   struct wpa_driver_associate_params *params)
45518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
45528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
45538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
45548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int count = 0;
45558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
45578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode)) {
45598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
45608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "IBSS mode");
45618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
45628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
45638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtretry:
45658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
45668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
45678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
45688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
45708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    NL80211_CMD_JOIN_IBSS, 0);
45718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
45728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
45748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
45758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
45778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  params->ssid, params->ssid_len);
45788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
45798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		params->ssid);
45808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(drv->ssid, params->ssid, params->ssid_len);
45818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->ssid_len = params->ssid_len;
45828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
45848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
45858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = nl80211_set_conn_keys(params, msg);
45878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret)
45888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
45898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->wpa_ie) {
45918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_DEBUG,
45928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    "  * Extra IEs for Beacon/Probe Response frames",
45938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    params->wpa_ie, params->wpa_ie_len);
45948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
45958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->wpa_ie);
45968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
45978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
45988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
45998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
46008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
46018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Join IBSS failed: ret=%d (%s)",
46028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ret, strerror(-ret));
46038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		count++;
46048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (ret == -EALREADY && count == 1) {
46058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
46068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "forced leave");
46078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nl80211_leave_ibss(drv);
46088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nlmsg_free(msg);
46098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto retry;
46108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
46118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
46128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
46138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
46148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = 0;
46158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Join IBSS request sent successfully");
46168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
46178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
46188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
46198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
46208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
46218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
46228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
46238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_connect(
46248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv,
46258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_associate_params *params)
46268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
46278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
46288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum nl80211_auth_type type;
46298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = 0;
46308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int algs;
46318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
46328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
46338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
46348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
46358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
46368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
46378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
46388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    NL80211_CMD_CONNECT, 0);
46398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
46408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
46418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->bssid) {
46428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * bssid=" MACSTR,
46438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(params->bssid));
46448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
46458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
46468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->freq) {
46478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
46488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
46498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
46508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->ssid) {
46518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
46528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  params->ssid, params->ssid_len);
46538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
46548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->ssid);
46558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->ssid_len > sizeof(drv->ssid))
46568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto nla_put_failure;
46578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(drv->ssid, params->ssid, params->ssid_len);
46588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->ssid_len = params->ssid_len;
46598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
46608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "  * IEs", params->wpa_ie, params->wpa_ie_len);
46618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->wpa_ie)
46628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
46638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->wpa_ie);
46648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
46658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	algs = 0;
46668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->auth_alg & WPA_AUTH_ALG_OPEN)
46678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		algs++;
46688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->auth_alg & WPA_AUTH_ALG_SHARED)
46698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		algs++;
46708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->auth_alg & WPA_AUTH_ALG_LEAP)
46718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		algs++;
46728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (algs > 1) {
46738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * Leave out Auth Type for automatic "
46748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "selection");
46758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto skip_auth_type;
46768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
46778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
46788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->auth_alg & WPA_AUTH_ALG_OPEN)
46798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		type = NL80211_AUTHTYPE_OPEN_SYSTEM;
46808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (params->auth_alg & WPA_AUTH_ALG_SHARED)
46818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		type = NL80211_AUTHTYPE_SHARED_KEY;
46828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (params->auth_alg & WPA_AUTH_ALG_LEAP)
46838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		type = NL80211_AUTHTYPE_NETWORK_EAP;
46848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (params->auth_alg & WPA_AUTH_ALG_FT)
46858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		type = NL80211_AUTHTYPE_FT;
46868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
46878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
46888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
46898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "  * Auth Type %d", type);
46908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
46918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
46928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtskip_auth_type:
46938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->wpa_ie && params->wpa_ie_len) {
46948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		enum nl80211_wpa_versions ver;
46958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
46968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->wpa_ie[0] == WLAN_EID_RSN)
46978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ver = NL80211_WPA_VERSION_2;
46988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else
46998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ver = NL80211_WPA_VERSION_1;
47008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * WPA Version %d", ver);
47028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
47038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
47048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->pairwise_suite != CIPHER_NONE) {
47068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int cipher;
47078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (params->pairwise_suite) {
47098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_WEP40:
47108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_WEP40;
47118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
47128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_WEP104:
47138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_WEP104;
47148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
47158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_CCMP:
47168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_CCMP;
47178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
47188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_TKIP:
47198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
47208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_TKIP;
47218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
47228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
47238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
47248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
47258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->group_suite != CIPHER_NONE) {
47278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int cipher;
47288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (params->group_suite) {
47308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_WEP40:
47318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_WEP40;
47328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
47338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_WEP104:
47348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_WEP104;
47358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
47368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_CCMP:
47378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_CCMP;
47388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
47398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_TKIP:
47408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
47418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_TKIP;
47428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
47438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
47448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
47458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
47468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
47488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    params->key_mgmt_suite == KEY_MGMT_PSK) {
47498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int mgmt = WLAN_AKM_SUITE_PSK;
47508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (params->key_mgmt_suite) {
47528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case KEY_MGMT_802_1X:
47538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			mgmt = WLAN_AKM_SUITE_8021X;
47548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
47558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case KEY_MGMT_PSK:
47568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
47578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			mgmt = WLAN_AKM_SUITE_PSK;
47588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
47598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
47608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
47618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
47628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = nl80211_set_conn_keys(params, msg);
47648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret)
47658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
47668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
47688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
47698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
47708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
47718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", ret, strerror(-ret));
47728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
47738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
47748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = 0;
47758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Connect request send successfully");
47768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
47788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
47798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
47808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
47828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_associate(
47858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	void *priv, struct wpa_driver_associate_params *params)
47868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
47878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
47888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
47898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
47908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
47918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->mode == IEEE80211_MODE_AP)
47938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return wpa_driver_nl80211_ap(drv, params);
47948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->mode == IEEE80211_MODE_IBSS)
47968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return wpa_driver_nl80211_ibss(drv, params);
47978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
47988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
47998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (wpa_driver_nl80211_set_mode(priv, params->mode) < 0)
48008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
48018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return wpa_driver_nl80211_connect(drv, params);
48028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
48038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->associated = 0;
48058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
48078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
48088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
48098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
48118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   drv->ifindex);
48128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
48138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    NL80211_CMD_ASSOCIATE, 0);
48148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
48168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->bssid) {
48178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * bssid=" MACSTR,
48188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(params->bssid));
48198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
48208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
48218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->freq) {
48228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
48238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
48248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->assoc_freq = params->freq;
48258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else
48268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->assoc_freq = 0;
48278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->ssid) {
48288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
48298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  params->ssid, params->ssid_len);
48308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
48318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->ssid);
48328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->ssid_len > sizeof(drv->ssid))
48338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto nla_put_failure;
48348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(drv->ssid, params->ssid, params->ssid_len);
48358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->ssid_len = params->ssid_len;
48368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
48378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_hexdump(MSG_DEBUG, "  * IEs", params->wpa_ie, params->wpa_ie_len);
48388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->wpa_ie)
48398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
48408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->wpa_ie);
48418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->pairwise_suite != CIPHER_NONE) {
48438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int cipher;
48448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (params->pairwise_suite) {
48468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_WEP40:
48478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_WEP40;
48488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
48498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_WEP104:
48508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_WEP104;
48518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
48528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_CCMP:
48538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_CCMP;
48548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
48558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_TKIP:
48568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
48578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_TKIP;
48588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
48598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
48608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * pairwise=0x%x", cipher);
48618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
48628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
48638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->group_suite != CIPHER_NONE) {
48658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int cipher;
48668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		switch (params->group_suite) {
48688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_WEP40:
48698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_WEP40;
48708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
48718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_WEP104:
48728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_WEP104;
48738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
48748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_CCMP:
48758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_CCMP;
48768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
48778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		case CIPHER_TKIP:
48788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		default:
48798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cipher = WLAN_CIPHER_SUITE_TKIP;
48808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
48818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
48828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * group=0x%x", cipher);
48838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
48848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
48858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211W
48878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
48888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
48898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211W */
48908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
48928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
48938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->prev_bssid) {
48948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * prev_bssid=" MACSTR,
48958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(params->prev_bssid));
48968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
48978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			params->prev_bssid);
48988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
48998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->p2p)
49018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "  * P2P group");
49028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
49048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
49058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
49068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
49078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", ret, strerror(-ret));
49088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_dump_scan(drv);
49098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
49108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
49118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = 0;
49128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Association request send "
49138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "successfully");
49148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
49168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
49178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
49188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
49198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
49228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    int ifindex, int mode)
49238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
49248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
49258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -ENOBUFS;
49268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
49288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
49298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
49308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
49328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_SET_INTERFACE, 0);
49338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
49348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
49358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
49378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!ret)
49388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
49398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
49408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
49418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   " %d (%s)", ifindex, mode, ret, strerror(-ret));
49428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
49438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
49448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_set_mode(void *priv, int mode)
49478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
49488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
49498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
49508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
49518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int nlmode;
49528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
49538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (mode) {
49558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case 0:
49568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nlmode = NL80211_IFTYPE_STATION;
49578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
49588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case 1:
49598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nlmode = NL80211_IFTYPE_ADHOC;
49608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
49618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case 2:
49628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nlmode = NL80211_IFTYPE_AP;
49638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
49648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
49658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
49668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
49678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nl80211_set_mode(drv, drv->ifindex, nlmode) == 0) {
49698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->nlmode = nlmode;
49708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = 0;
49718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto done;
49728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
49738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nlmode == drv->nlmode) {
49758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
49768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "requested mode - ignore error");
49778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = 0;
49788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto done; /* Already in the requested mode */
49798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
49808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
49818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* mac80211 doesn't allow mode changes while the device is up, so
49828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * take the device down, try to set the mode again, and bring the
49838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * device back up.
49848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
49858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
49868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "interface down");
49878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < 10; i++) {
49888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0) ==
49898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0) {
49908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* Try to set the mode again while the interface is
49918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * down */
49928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
49938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname,
49948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						  1))
49958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				ret = -1;
49968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (!ret)
49978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
49988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		} else
49998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Failed to set "
50008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "interface down");
50018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_sleep(0, 100000);
50028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
50038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!ret) {
50058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
50068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "interface is down");
50078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->nlmode = nlmode;
50088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
50098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtdone:
50118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!ret && nlmode == NL80211_IFTYPE_AP) {
50128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Setup additional AP mode functionality if needed */
5013c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		if (!drv->no_monitor_iface_capab && drv->monitor_ifidx < 0 &&
5014c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		    nl80211_create_monitor_interface(drv) &&
5015c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt		    !drv->no_monitor_iface_capab)
50168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
50178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (!ret && nlmode != NL80211_IFTYPE_AP) {
50188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Remove additional AP mode functionality */
50198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_remove_monitor_interface(drv);
50208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->beacon_set = 0;
50218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
50228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret)
50248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
50258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "from %d failed", nlmode, drv->nlmode);
50268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
50288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
50298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_get_capa(void *priv,
50328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       struct wpa_driver_capa *capa)
50338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
50348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
50358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
50368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!drv->has_capability)
50378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
50388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(capa, &drv->capa, sizeof(*capa));
50398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
50408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
50418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_set_operstate(void *priv, int state)
50448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
50458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
50468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
50478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
50498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   __func__, drv->operstate, state, state ? "UP" : "DORMANT");
50508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->operstate = state;
50518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1,
50528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      state ? IF_OPER_UP : IF_OPER_DORMANT);
50538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
50548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_set_supp_port(void *priv, int authorized)
50578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
50588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
50598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
50608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
50618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl80211_sta_flag_update upd;
50628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
50648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
50658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
50668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
50688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_SET_STATION, 0);
50698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
50718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    if_nametoindex(bss->ifname));
50728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
50738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&upd, 0, sizeof(upd));
50758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED);
50768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (authorized)
50778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
50788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
50798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
50818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
50828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
50838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
50848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
508675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen/* Set kernel driver on given frequency (MHz) */
508775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
50888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
508975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct i802_bss *bss = priv;
509075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct wpa_driver_nl80211_data *drv = bss->drv;
509175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	return wpa_driver_nl80211_set_freq(drv, freq->freq, freq->ht_enabled,
509275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen					   freq->sec_channel_offset);
50938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
50948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
509675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen#if defined(HOSTAPD) || defined(CONFIG_AP)
50978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
50988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic inline int min_int(int a, int b)
50998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
51008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (a < b)
51018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return a;
51028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return b;
51038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
51048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int get_key_handler(struct nl_msg *msg, void *arg)
51078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
51088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
51098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
51108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
51128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
51138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
51158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * TODO: validate the key index and mac address!
51168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Otherwise, there's a race condition as soon as
51178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * the kernel starts sending key notifications.
51188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
51198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_KEY_SEQ])
51218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]),
51228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6));
51238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
51248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
51258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
51288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   int idx, u8 *seq)
51298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
51308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
51318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
51328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
51338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
51358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
51368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
51378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
51398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_GET_KEY, 0);
51408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (addr)
51428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
51438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);
51448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
51458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memset(seq, 0, 6);
51478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, get_key_handler, seq);
51498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
51508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
51518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
51528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates,
51558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      int mode)
51568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
51578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
51588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
51598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
51608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 rates[NL80211_MAX_SUPP_RATES];
51618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 rates_len = 0;
51628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
51638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
51658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
51668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
51678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
51698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    NL80211_CMD_SET_BSS, 0);
51708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++)
51728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		rates[rates_len++] = basic_rates[i] / 5;
51738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
51758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
51778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
51798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
51808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
51818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
51828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_set_rts(void *priv, int rts)
51858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
51868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
51878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
51888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
51898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -ENOBUFS;
51908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 val;
51918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
51938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
51948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
51958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
51968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (rts >= 2347)
51978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val = (u32) -1;
51988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
51998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val = rts;
52008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
52028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_SET_WIPHY, 0);
52038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
52048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val);
52058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
52078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!ret)
52088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
52098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
52108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
52118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "%d (%s)", rts, ret, strerror(-ret));
52128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
52138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
52148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_set_frag(void *priv, int frag)
52178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
52188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
52198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
52208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
52218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -ENOBUFS;
52228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 val;
52238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
52258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
52268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
52278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (frag >= 2346)
52298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val = (u32) -1;
52308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
52318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		val = frag;
52328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
52348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_SET_WIPHY, 0);
52358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
52368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val);
52378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
52398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!ret)
52408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
52418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
52428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
52438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "%d: %d (%s)", frag, ret, strerror(-ret));
52448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
52458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
52468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_flush(void *priv)
52498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
52508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
52518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
52528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
52538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
52558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
52568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
52578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
52598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_DEL_STATION, 0);
52608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
52628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * XXX: FIX! this needs to flush all VLANs too
52638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
52648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
52658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    if_nametoindex(bss->ifname));
52668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
52688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
52698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
52708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
52718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int get_sta_handler(struct nl_msg *msg, void *arg)
52748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
52758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
52768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
52778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostap_sta_driver_data *data = arg;
52788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *stats[NL80211_STA_INFO_MAX + 1];
52798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
52808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
52818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
52828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
52838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
52848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		[NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
52858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	};
52868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
52888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
52898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
52918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * TODO: validate the interface and mac address!
52928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Otherwise, there's a race condition as soon as
52938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * the kernel starts sending station notifications.
52948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
52958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
52968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!tb[NL80211_ATTR_STA_INFO]) {
52978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "sta stats missing!");
52988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
52998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
53008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nla_parse_nested(stats, NL80211_STA_INFO_MAX,
53018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     tb[NL80211_ATTR_STA_INFO],
53028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     stats_policy)) {
53038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "failed to parse nested attributes!");
53048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL_SKIP;
53058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
53068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (stats[NL80211_STA_INFO_INACTIVE_TIME])
53088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->inactive_msec =
53098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]);
53108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (stats[NL80211_STA_INFO_RX_BYTES])
53118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]);
53128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (stats[NL80211_STA_INFO_TX_BYTES])
53138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]);
53148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (stats[NL80211_STA_INFO_RX_PACKETS])
53158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->rx_packets =
53168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]);
53178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (stats[NL80211_STA_INFO_TX_PACKETS])
53188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		data->tx_packets =
53198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
53208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
53228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
53238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
53258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      const u8 *addr)
53268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
53278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
53288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
53298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
53308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(data, 0, sizeof(*data));
53328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
53338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
53348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
53358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
53378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_GET_STATION, 0);
53388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
53408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
53418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, get_sta_handler, data);
53438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
53448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
53458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
53468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_set_tx_queue_params(void *priv, int queue, int aifs,
53498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    int cw_min, int cw_max, int burst_time)
53508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
53518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
53528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
53538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
53548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *txq, *params;
53558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
53578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
53588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
53598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
53618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_SET_WIPHY, 0);
53628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
53648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
53668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!txq)
53678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
53688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* We are only sending parameters for a single TXQ at a time */
53708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	params = nla_nest_start(msg, 1);
53718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!params)
53728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
53738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (queue) {
53758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case 0:
53768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO);
53778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
53788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case 1:
53798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI);
53808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
53818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case 2:
53828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE);
53838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
53848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case 3:
53858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK);
53868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
53878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
53888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Burst time is configured in units of 0.1 msec and TXOP parameter in
53898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * 32 usec, so need to convert the value here. */
53908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U16(msg, NL80211_TXQ_ATTR_TXOP, (burst_time * 100 + 16) / 32);
53918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min);
53928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max);
53938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U8(msg, NL80211_TXQ_ATTR_AIFS, aifs);
53948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_nest_end(msg, params);
53968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_nest_end(msg, txq);
53988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
54008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
54018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
54028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
54038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
54048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_set_bss(void *priv, int cts, int preamble, int slot,
54078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			int ht_opmode)
54088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
54098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
54108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
54118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
54128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
54148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
54158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
54168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
54188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    NL80211_CMD_SET_BSS, 0);
54198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cts >= 0)
54218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts);
54228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (preamble >= 0)
54238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble);
54248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (slot >= 0)
54258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot);
54268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ht_opmode >= 0)
54278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode);
54288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
54298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
54318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
54328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
54338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
54348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_set_cts_protect(void *priv, int value)
54378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
54388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return i802_set_bss(priv, value, -1, -1, -1);
54398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
54408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_set_preamble(void *priv, int value)
54438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
54448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return i802_set_bss(priv, -1, value, -1, -1);
54458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
54468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_set_short_slot_time(void *priv, int value)
54498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
54508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return i802_set_bss(priv, -1, -1, value, -1);
54518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
54528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_set_sta_vlan(void *priv, const u8 *addr,
54558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     const char *ifname, int vlan_id)
54568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
54578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
54588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
54598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
54608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -ENOBUFS;
54618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
54638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
54648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
54658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
54678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_SET_STATION, 0);
54688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
54708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    if_nametoindex(bss->ifname));
54718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
54728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN,
54738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    if_nametoindex(ifname));
54748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
54768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret < 0) {
54778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
54788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
54798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MAC2STR(addr), ifname, vlan_id, ret,
54808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   strerror(-ret));
54818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
54828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
54838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
54848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
54858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_set_ht_params(void *priv, const u8 *ht_capab,
54888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      size_t ht_capab_len, const u8 *ht_oper,
54898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      size_t ht_oper_len)
54908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
54918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ht_oper_len >= 6) {
54928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* ht opmode uses 16bit in octet 5 & 6 */
54938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u16 ht_opmode = le_to_host16(((u16 *) ht_oper)[2]);
54948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return i802_set_bss(priv, -1, -1, -1, ht_opmode);
54958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else
54968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
54978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
54988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
54998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
55008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_get_inact_sec(void *priv, const u8 *addr)
55018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
55028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostap_sta_driver_data data;
55038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
55048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
55058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data.inactive_msec = (unsigned long) -1;
55068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = i802_read_sta_data(priv, &data, addr);
55078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret || data.inactive_msec == (unsigned long) -1)
55088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
55098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return data.inactive_msec / 1000;
55108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
55118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
55128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
55138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_sta_clear_stats(void *priv, const u8 *addr)
55148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
55158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if 0
55168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* TODO */
55178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif
55188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
55198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
55208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
55218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
55228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
55238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   int reason)
55248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
55258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
55268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee80211_mgmt mgmt;
55278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
55288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memset(&mgmt, 0, sizeof(mgmt));
55298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
55308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  WLAN_FC_STYPE_DEAUTH);
55318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(mgmt.da, addr, ETH_ALEN);
55328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(mgmt.sa, own_addr, ETH_ALEN);
55338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
55348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt.u.deauth.reason_code = host_to_le16(reason);
55358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
55368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    IEEE80211_HDRLEN +
55378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    sizeof(mgmt.u.deauth));
55388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
55398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
55408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
55418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
55428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     int reason)
55438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
55448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
55458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee80211_mgmt mgmt;
55468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
55478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memset(&mgmt, 0, sizeof(mgmt));
55488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
55498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  WLAN_FC_STYPE_DISASSOC);
55508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(mgmt.da, addr, ETH_ALEN);
55518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(mgmt.sa, own_addr, ETH_ALEN);
55528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
55538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	mgmt.u.disassoc.reason_code = host_to_le16(reason);
55548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
55558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    IEEE80211_HDRLEN +
55568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					    sizeof(mgmt.u.disassoc));
55578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
55588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
55598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD || CONFIG_AP */
55608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
55618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
55628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
556375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
556475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
556575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	int i;
556675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	int *old;
556775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
556875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d",
556975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		   ifidx);
557075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	for (i = 0; i < drv->num_if_indices; i++) {
557175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		if (drv->if_indices[i] == 0) {
557275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			drv->if_indices[i] = ifidx;
557375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			return;
557475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		}
557575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	}
557675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
557775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (drv->if_indices != drv->default_if_indices)
557875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		old = drv->if_indices;
557975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	else
558075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		old = NULL;
558175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
558275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	drv->if_indices = os_realloc(old,
558375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen				     sizeof(int) * (drv->num_if_indices + 1));
558475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (!drv->if_indices) {
558575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		if (!old)
558675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			drv->if_indices = drv->default_if_indices;
558775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		else
558875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			drv->if_indices = old;
558975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
559075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			   "interfaces");
559175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
559275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		return;
559375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	} else if (!old)
559475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		os_memcpy(drv->if_indices, drv->default_if_indices,
559575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			  sizeof(drv->default_if_indices));
559675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	drv->if_indices[drv->num_if_indices] = ifidx;
559775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	drv->num_if_indices++;
559875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
559975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
560075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
560175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
560275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
560375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	int i;
560475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
560575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	for (i = 0; i < drv->num_if_indices; i++) {
560675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		if (drv->if_indices[i] == ifidx) {
560775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			drv->if_indices[i] = 0;
560875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			break;
560975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		}
561075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	}
561175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
561275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
561375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
561475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
561575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
561675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	int i;
561775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
561875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	for (i = 0; i < drv->num_if_indices; i++)
561975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		if (drv->if_indices[i] == ifidx)
562075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			return 1;
562175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
562275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	return 0;
562375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
562475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
562575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
562675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
562775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen                            const char *bridge_ifname)
562875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
562975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct i802_bss *bss = priv;
563075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct wpa_driver_nl80211_data *drv = bss->drv;
563175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	char name[IFNAMSIZ + 1];
563275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
563375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
563475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
563575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		   " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
563675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (val) {
563775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		if (!if_nametoindex(name)) {
563875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			if (nl80211_create_iface(drv, name,
563975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen						 NL80211_IFTYPE_AP_VLAN,
564075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen						 NULL, 1) < 0)
564175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen				return -1;
564275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			if (bridge_ifname &&
564375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			    linux_br_add_if(drv->ioctl_sock, bridge_ifname,
564475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen					    name) < 0)
564575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen				return -1;
564675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		}
564775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		linux_set_iface_flags(drv->ioctl_sock, name, 1);
564875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		return i802_set_sta_vlan(priv, addr, name, 0);
564975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	} else {
565075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		i802_set_sta_vlan(priv, addr, bss->ifname, 0);
565175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
565275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen						    name);
565375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	}
565475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
565575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
565675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
565775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
565875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
565975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct wpa_driver_nl80211_data *drv = eloop_ctx;
566075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct sockaddr_ll lladdr;
566175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	unsigned char buf[3000];
566275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	int len;
566375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	socklen_t fromlen = sizeof(lladdr);
566475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
566575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	len = recvfrom(sock, buf, sizeof(buf), 0,
566675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		       (struct sockaddr *)&lladdr, &fromlen);
566775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (len < 0) {
566875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		perror("recv");
566975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		return;
567075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	}
567175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
567275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (have_ifidx(drv, lladdr.sll_ifindex))
567375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
567475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
567575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
567675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
56778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
56788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     struct i802_bss *bss,
56798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     const char *brname, const char *ifname)
56808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
56818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifindex;
56828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char in_br[IFNAMSIZ];
56838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
56848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_strlcpy(bss->brname, brname, IFNAMSIZ);
56858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ifindex = if_nametoindex(brname);
56868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ifindex == 0) {
56878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
56888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Bridge was configured, but the bridge device does
56898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * not exist. Try to add it now.
56908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
56918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (linux_br_add(drv->ioctl_sock, brname) < 0) {
56928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
56938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "bridge interface %s: %s",
56948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   brname, strerror(errno));
56958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
56968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
56978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		bss->added_bridge = 1;
56988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		add_ifidx(drv, if_nametoindex(brname));
56998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
57008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (linux_br_get(in_br, ifname) == 0) {
57028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_strcmp(in_br, brname) == 0)
57038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 0; /* already in the bridge */
57048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
57068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "bridge %s", ifname, in_br);
57078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (linux_br_del_if(drv->ioctl_sock, in_br, ifname) < 0) {
57088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "nl80211: Failed to "
57098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "remove interface %s from bridge "
57108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "%s: %s",
57118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   ifname, brname, strerror(errno));
57128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
57138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
57148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
57158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
57178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   ifname, brname);
57188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (linux_br_add_if(drv->ioctl_sock, brname, ifname) < 0) {
57198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to add interface %s "
57208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "into bridge %s: %s",
57218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   ifname, brname, strerror(errno));
57228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
57238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
57248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss->added_if_into_bridge = 1;
57258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
57278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
57288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void *i802_init(struct hostapd_data *hapd,
57318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       struct wpa_init_params *params)
57328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
57338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv;
57348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss;
57358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t i;
57368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char brname[IFNAMSIZ];
57378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifindex, br_ifindex;
57388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int br_added = 0;
57398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bss = wpa_driver_nl80211_init(hapd, params->ifname, NULL);
57418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss == NULL)
57428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
57438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv = bss->drv;
57458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->nlmode = NL80211_IFTYPE_AP;
57468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (linux_br_get(brname, params->ifname) == 0) {
57478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
57488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   params->ifname, brname);
57498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		br_ifindex = if_nametoindex(brname);
57508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
57518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		brname[0] = '\0';
57528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		br_ifindex = 0;
57538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
57548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
57568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->if_indices = drv->default_if_indices;
57578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < params->num_bridge; i++) {
57588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (params->bridge[i]) {
57598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ifindex = if_nametoindex(params->bridge[i]);
57608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ifindex)
57618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				add_ifidx(drv, ifindex);
57628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ifindex == br_ifindex)
57638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				br_added = 1;
57648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
57658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
57668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!br_added && br_ifindex &&
57678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (params->num_bridge == 0 || !params->bridge[0]))
57688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		add_ifidx(drv, br_ifindex);
57698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* start listening for EAPOL on the default AP interface */
57718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	add_ifidx(drv, drv->ifindex);
57728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0))
57748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
57758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->bssid) {
57778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (linux_set_ifhwaddr(drv->ioctl_sock, bss->ifname,
57788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       params->bssid))
57798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			goto failed;
57808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
57818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_AP)) {
57838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
57848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "into AP mode", bss->ifname);
57858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
57868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
57878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (params->num_bridge && params->bridge[0] &&
57898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
57908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
57918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1))
57938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
57948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
57958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
57968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->eapol_sock < 0) {
57978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)");
57988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
57998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
58008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
58028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	{
58038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		printf("Could not register read socket for eapol\n");
58048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
58058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
58068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, params->own_addr))
58088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto failed;
58098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return bss;
58118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtfailed:
58138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl80211_remove_monitor_interface(drv);
58148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rfkill_deinit(drv->rfkill);
58158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	netlink_deinit(drv->netlink);
58168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->ioctl_sock >= 0)
58178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		close(drv->ioctl_sock);
58188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genl_family_put(drv->nl80211);
58208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cache_free(drv->nl_cache);
58218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl80211_handle_destroy(drv->nl_handle);
58228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cb_put(drv->nl_cb);
58238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
58248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(drv);
58268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
58278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
58288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void i802_deinit(void *priv)
58318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
58328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_driver_nl80211_deinit(priv);
58338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
58348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
58368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic enum nl80211_iftype wpa_driver_nl80211_if_type(
58398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum wpa_driver_if_type type)
58408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
58418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (type) {
58428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_IF_STATION:
58438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL80211_IFTYPE_STATION;
58448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_IF_P2P_CLIENT:
58458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_IF_P2P_GROUP:
58468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL80211_IFTYPE_P2P_CLIENT;
58478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_IF_AP_VLAN:
58488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL80211_IFTYPE_AP_VLAN;
58498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_IF_AP_BSS:
58508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL80211_IFTYPE_AP;
58518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case WPA_IF_P2P_GO:
58528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NL80211_IFTYPE_P2P_GO;
58538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
58548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
58558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
58568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
58598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
58618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
58628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv;
58638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_for_each(drv, &global->interfaces,
58648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 struct wpa_driver_nl80211_data, list) {
58658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_memcmp(addr, drv->addr, ETH_ALEN) == 0)
58668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 1;
58678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
58688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
58698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
58708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
58738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      u8 *new_addr)
58748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
58758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int idx;
58768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!drv->global)
58788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
58798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(new_addr, drv->addr, ETH_ALEN);
58818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (idx = 0; idx < 64; idx++) {
58828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		new_addr[0] = drv->addr[0] | 0x02;
58838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		new_addr[0] ^= idx << 2;
58848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!nl80211_addr_in_use(drv->global, new_addr))
58858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
58868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
58878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (idx == 64)
58888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
58898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Assigned new P2P Interface Address "
58918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   MACSTR, MAC2STR(new_addr));
58928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
58948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
58958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
58978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
58998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
59008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     const char *ifname, const u8 *addr,
59018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     void *bss_ctx, void **drv_priv,
59028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     char *force_ifname, u8 *if_addr,
59038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     const char *bridge)
59048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
59058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
59068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
59078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifidx;
59088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
59098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *new_bss = NULL;
59108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (type == WPA_IF_AP_BSS) {
59128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		new_bss = os_zalloc(sizeof(*new_bss));
59138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (new_bss == NULL)
59148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
59158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
59168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
59178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (addr)
59198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(if_addr, addr, ETH_ALEN);
59208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ifidx = nl80211_create_iface(drv, ifname,
59218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     wpa_driver_nl80211_if_type(type), addr,
59228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     0);
59238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ifidx < 0) {
59248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
59258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(new_bss);
59268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
59278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
59288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
59298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!addr &&
59318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, if_addr) < 0) {
59328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_remove_iface(drv, ifidx);
59338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
59348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
59358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
59378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!addr &&
59388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
59398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	     type == WPA_IF_P2P_GO)) {
59408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Enforce unique P2P Interface Address */
59418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN];
59428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, own_addr)
59448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    < 0 ||
59458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    linux_get_ifhwaddr(drv->ioctl_sock, ifname, new_addr) < 0)
59468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		{
59478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nl80211_remove_iface(drv, ifidx);
59488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
59498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
59508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_memcmp(own_addr, new_addr, ETH_ALEN) == 0) {
59518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
59528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "for P2P group interface");
59538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (nl80211_p2p_interface_addr(drv, new_addr) < 0) {
59548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				nl80211_remove_iface(drv, ifidx);
59558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return -1;
59568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
59578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (linux_set_ifhwaddr(drv->ioctl_sock, ifname,
59588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					       new_addr) < 0) {
59598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				nl80211_remove_iface(drv, ifidx);
59608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return -1;
59618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
59628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(if_addr, new_addr, ETH_ALEN);
59638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
59648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
59658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
59668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
59688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bridge &&
59698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
59708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
59718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "interface %s to a bridge %s", ifname, bridge);
59728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nl80211_remove_iface(drv, ifidx);
59738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(new_bss);
59748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
59758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
59768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (type == WPA_IF_AP_BSS) {
59788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (linux_set_iface_flags(drv->ioctl_sock, ifname, 1)) {
59798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nl80211_remove_iface(drv, ifidx);
59808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(new_bss);
59818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return -1;
59828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
59838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
59848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		new_bss->ifindex = ifidx;
59858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		new_bss->drv = drv;
59868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		new_bss->next = drv->first_bss.next;
59878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->first_bss.next = new_bss;
59888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (drv_priv)
59898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			*drv_priv = new_bss;
59908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
59918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
59928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
59948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
59958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
59978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_if_remove(void *priv,
59988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					enum wpa_driver_if_type type,
59998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					const char *ifname)
60008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
60018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
60028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
60038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ifindex = if_nametoindex(ifname);
60048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d",
60068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   __func__, type, ifname, ifindex);
60078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ifindex <= 0)
60088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
60098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
60118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss->added_if_into_bridge) {
60128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (linux_br_del_if(drv->ioctl_sock, bss->brname, bss->ifname)
60138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    < 0)
60148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
60158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "interface %s from bridge %s: %s",
60168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   bss->ifname, bss->brname, strerror(errno));
60178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
60188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss->added_bridge) {
60198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (linux_br_del(drv->ioctl_sock, bss->brname) < 0)
60208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
60218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "bridge %s: %s",
60228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   bss->brname, strerror(errno));
60238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
60248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
60258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl80211_remove_iface(drv, ifindex);
60278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
60298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (type != WPA_IF_AP_BSS)
60308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
60318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (bss != &drv->first_bss) {
60338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct i802_bss *tbss;
60348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		for (tbss = &drv->first_bss; tbss; tbss = tbss->next) {
60368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (tbss->next == bss) {
60378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				tbss->next = bss->next;
60388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				os_free(bss);
60398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				bss = NULL;
60408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				break;
60418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
60428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
60438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (bss)
60448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_INFO, "nl80211: %s - could not find "
60458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "BSS %p in the list", __func__, bss);
60468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
60478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD */
60488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
60508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
60518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int cookie_handler(struct nl_msg *msg, void *arg)
60548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
60558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *tb[NL80211_ATTR_MAX + 1];
60568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
60578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u64 *cookie = arg;
60588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
60598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  genlmsg_attrlen(gnlh, 0), NULL);
60608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (tb[NL80211_ATTR_COOKIE])
60618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
60628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NL_SKIP;
60638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
60648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv,
60678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  unsigned int freq, unsigned int wait,
60688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  const u8 *buf, size_t buf_len,
60698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  u64 *cookie_out)
60708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
60718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
60728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u64 cookie;
60738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
60748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
60768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
60778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
60788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
60808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    NL80211_CMD_FRAME, 0);
60818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
60838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
60848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
60858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
60868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf);
60878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cookie = 0;
60898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
60908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
60918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
60928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
60938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", ret, strerror(-ret));
60948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
60958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
60968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted; "
60978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "cookie 0x%llx", (long long unsigned int) cookie);
60988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
60998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cookie_out)
61008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*cookie_out = cookie;
61018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
61038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
61048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
61058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
61068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
61098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  unsigned int wait_time,
61108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  const u8 *dst, const u8 *src,
61118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  const u8 *bssid,
61128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					  const u8 *data, size_t data_len)
61138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
61148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
61158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
61168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret = -1;
61178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *buf;
61188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee80211_hdr *hdr;
61198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
61218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "wait=%d ms)", drv->ifindex, wait_time);
61228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	buf = os_zalloc(24 + data_len);
61248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (buf == NULL)
61258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return ret;
61268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(buf + 24, data, data_len);
61278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = (struct ieee80211_hdr *) buf;
61288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr->frame_control =
61298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
61308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(hdr->addr1, dst, ETH_ALEN);
61318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(hdr->addr2, src, ETH_ALEN);
61328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(hdr->addr3, bssid, ETH_ALEN);
61338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nlmode == NL80211_IFTYPE_AP)
61358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len);
61368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
61378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = nl80211_send_frame_cmd(drv, freq, wait_time, buf,
61388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     24 + data_len,
61398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     &drv->send_action_cookie);
61408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(buf);
61428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
61438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
61448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
61478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
61488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
61498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
61508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
61518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
61528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
61548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
61558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
61568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
61588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    NL80211_CMD_FRAME_WAIT_CANCEL, 0);
61598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
61618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie);
61628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
61648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
61658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret)
61668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
61678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", ret, strerror(-ret));
61688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
61708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
61718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
61728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
61758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						unsigned int duration)
61768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
61778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
61788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
61798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
61808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
61818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u64 cookie;
61828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
61848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
61858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
61868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
61888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    NL80211_CMD_REMAIN_ON_CHANNEL, 0);
61898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
61918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
61928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
61938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
61948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cookie = 0;
61958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
61968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == 0) {
61978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
61988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "0x%llx for freq=%u MHz duration=%u",
61998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (long long unsigned int) cookie, freq, duration);
62008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->remain_on_chan_cookie = cookie;
62018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
62028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
62038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
62048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "(freq=%d duration=%u): %d (%s)",
62058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   freq, duration, ret, strerror(-ret));
62068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
62078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
62088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
62098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_cancel_remain_on_channel(void *priv)
62128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
62138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
62148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
62158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
62168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
62178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!drv->pending_remain_on_chan) {
62198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: No pending remain-on-channel "
62208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "to cancel");
62218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
62228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
62238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Cancel remain-on-channel with cookie "
62258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "0x%llx",
62268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (long long unsigned int) drv->remain_on_chan_cookie);
62278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
62298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
62308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
62318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
62338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, 0);
62348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
62368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie);
62378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
62398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret == 0)
62408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
62418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
62428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "%d (%s)", ret, strerror(-ret));
62438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
62448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
62458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
62468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_probe_req_report(void *priv, int report)
62498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
62508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
62518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
62528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nlmode != NL80211_IFTYPE_STATION) {
62548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: probe_req_report control only "
62558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "allowed in station mode (iftype=%d)",
62568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   drv->nlmode);
62578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
62588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
62598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!report) {
62618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (drv->nl_handle_preq) {
62628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			eloop_unregister_read_sock(
62638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				nl_socket_get_fd(drv->nl_handle_preq));
62648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nl_cache_free(drv->nl_cache_preq);
62658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			nl80211_handle_destroy(drv->nl_handle_preq);
62668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			drv->nl_handle_preq = NULL;
62678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
62688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
62698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
62708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nl_handle_preq) {
62728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting "
62738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "already on!");
62748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
62758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
62768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->nl_handle_preq = nl80211_handle_alloc(drv->nl_cb);
62788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nl_handle_preq == NULL) {
62798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate "
62808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "netlink callbacks (preq)");
62818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto out_err1;
62828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
62838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (genl_connect(drv->nl_handle_preq)) {
62858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to connect to "
62868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "generic netlink (preq)");
62878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto out_err2;
62888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
62898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
62908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
62918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_LIBNL20
62928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (genl_ctrl_alloc_cache(drv->nl_handle_preq,
62938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  &drv->nl_cache_preq) < 0) {
62948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
62958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "netlink cache (preq)");
62968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto out_err2;
62978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
62988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* CONFIG_LIBNL20 */
62998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->nl_cache_preq = genl_ctrl_alloc_cache(drv->nl_handle_preq);
63008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nl_cache_preq == NULL) {
63018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
63028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "netlink cache (preq)");
63038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto out_err2;
63048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
63058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_LIBNL20 */
63068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (nl80211_register_frame(drv, drv->nl_handle_preq,
63088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   (WLAN_FC_TYPE_MGMT << 2) |
63098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   (WLAN_FC_STYPE_PROBE_REQ << 4),
63108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   NULL, 0) < 0) {
63118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto out_err3;
63128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
63138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_preq),
63158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 wpa_driver_nl80211_event_receive, drv,
63168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 drv->nl_handle_preq);
63178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
63198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt out_err3:
63218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl_cache_free(drv->nl_cache_preq);
63228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt out_err2:
63238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nl80211_handle_destroy(drv->nl_handle_preq);
63248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->nl_handle_preq = NULL;
63258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt out_err1:
63268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
63278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
63288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
63318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				     int ifindex, int disabled)
63328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
63338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
63348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nlattr *bands, *band;
63358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
63368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
63388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
63398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
63408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
63428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    NL80211_CMD_SET_TX_BITRATE_MASK, 0);
63438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
63448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
63468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!bands)
63478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
63488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
63508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything
63518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * else apart from 6, 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS
63528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * rates. All 5 GHz rates are left enabled.
63538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
63548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	band = nla_nest_start(msg, NL80211_BAND_2GHZ);
63558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!band)
63568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto nla_put_failure;
63578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
63588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		"\x0c\x12\x18\x24\x30\x48\x60\x6c");
63598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_nest_end(msg, band);
63608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_nest_end(msg, bands);
63628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
63648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
63658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ret) {
63668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
63678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(%s)", ret, strerror(-ret));
63688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
63698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
63718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
63738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
63748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
63758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
63768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_disable_11b_rates(void *priv, int disabled)
63798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
63808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
63818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
63828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	drv->disable_11b_rates = disabled;
63838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return nl80211_disable_11b_rates(drv, drv->ifindex, disabled);
63848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
63858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int wpa_driver_nl80211_deinit_ap(void *priv)
63888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
63898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
63908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
63918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (drv->nlmode != NL80211_IFTYPE_AP)
63928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
63938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_driver_nl80211_del_beacon(drv);
63948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA);
63958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
63968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
63988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void wpa_driver_nl80211_resume(void *priv)
63998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
64008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
64018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
64028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) {
64038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on "
64048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "resume event");
64058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
64068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
64078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
64108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  const u8 *ies, size_t ies_len)
64118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
64128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
64138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
64148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
64158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *data, *pos;
64168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t data_len;
64178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 own_addr[ETH_ALEN];
64188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, own_addr) < 0)
64208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
64218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (action != 1) {
64238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action "
64248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "action %d", action);
64258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
64268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
64278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/*
64298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Action frame payload:
64308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Category[1] = 6 (Fast BSS Transition)
64318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Action[1] = 1 (Fast BSS Transition Request)
64328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * STA Address
64338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Target AP Address
64348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * FT IEs
64358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 */
64368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data_len = 2 + 2 * ETH_ALEN + ies_len;
64388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data = os_malloc(data_len);
64398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (data == NULL)
64408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
64418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos = data;
64428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*pos++ = 0x06; /* FT Action category */
64438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	*pos++ = action;
64448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, own_addr, ETH_ALEN);
64458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += ETH_ALEN;
64468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, target_ap, ETH_ALEN);
64478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	pos += ETH_ALEN;
64488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(pos, ies, ies_len);
64498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0,
64518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     drv->bssid, own_addr, drv->bssid,
64528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					     data, data_len);
64538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(data);
64548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ret;
64568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
64578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
64608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
64618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
64628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
64638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg, *cqm = NULL;
64648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
64668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "hysteresis=%d", threshold, hysteresis);
64678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
64698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
64708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
64718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
64738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    0, NL80211_CMD_SET_CQM, 0);
64748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
64768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cqm = nlmsg_alloc();
64788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cqm == NULL)
64798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
64808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_THOLD, threshold);
64828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(cqm, NL80211_ATTR_CQM_RSSI_HYST, hysteresis);
64838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nla_put_nested(msg, NL80211_ATTR_CQM, cqm);
64848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
64868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
64878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = NULL;
64888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtnla_put_failure:
64908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cqm)
64918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		nlmsg_free(cqm);
64928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	nlmsg_free(msg);
64938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
64948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
64958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
64978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
64988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
64998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
65008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
65018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res;
65028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(si, 0, sizeof(*si));
65048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = nl80211_get_link_signal(drv, si);
65058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res != 0)
65068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return res;
65078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return nl80211_get_link_noise(drv, si);
65098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
65108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
65138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      int encrypt)
65148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
65158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
65168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
65178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt);
65188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
65198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_set_intra_bss(void *priv, int enabled)
65228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
65238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
65248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
65258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl_msg *msg;
65268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = nlmsg_alloc();
65288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!msg)
65298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -ENOMEM;
65308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
65328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    NL80211_CMD_SET_BSS, 0);
65338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
65358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, !enabled);
65368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return send_and_recv_msgs(drv, msg, NULL, NULL);
65388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt nla_put_failure:
65398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -ENOBUFS;
65408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
65418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int nl80211_set_param(void *priv, const char *param)
65448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
65458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "nl80211: driver param='%s'", param);
65468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (param == NULL)
65478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
65488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_P2P
65508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_strstr(param, "use_p2p_group_interface=1")) {
65518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct i802_bss *bss = priv;
65528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct wpa_driver_nl80211_data *drv = bss->drv;
65538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
65558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "interface");
65568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
65578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
65588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
65598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_P2P */
65608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
65628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
65638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void * nl80211_global_init(void)
65668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
65678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl80211_global *global;
65688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	global = os_zalloc(sizeof(*global));
65698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global == NULL)
65708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
65718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	dl_list_init(&global->interfaces);
65728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return global;
65738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
65748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void nl80211_global_deinit(void *priv)
65778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
65788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct nl80211_global *global = priv;
65798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (global == NULL)
65808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
65818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!dl_list_empty(&global->interfaces)) {
65828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_ERROR, "nl80211: %u interface(s) remain at "
65838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "nl80211_global_deinit",
65848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   dl_list_len(&global->interfaces));
65858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
65868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(global);
65878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
65888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char * nl80211_get_radio_name(void *priv)
65918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
65928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct i802_bss *bss = priv;
65938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpa_driver_nl80211_data *drv = bss->drv;
65948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return drv->phyname;
65958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
65968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
65978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
659875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid,
659975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen			 const u8 *pmkid)
660075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
660175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct nl_msg *msg;
660275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
660375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	msg = nlmsg_alloc();
660475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (!msg)
660575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		return -ENOMEM;
660675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
660775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	genlmsg_put(msg, 0, 0, genl_family_get_id(bss->drv->nl80211), 0, 0,
660875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		    cmd, 0);
660975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
661075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
661175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (pmkid)
661275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		NLA_PUT(msg, NL80211_ATTR_PMKID, 16, pmkid);
661375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	if (bssid)
661475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
661575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
661675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
661775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen nla_put_failure:
661875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	return -ENOBUFS;
661975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
662075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
662175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
662275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic int nl80211_add_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
662375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
662475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct i802_bss *bss = priv;
662575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR, MAC2STR(bssid));
662675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	return nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, bssid, pmkid);
662775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
662875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
662975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
663075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic int nl80211_remove_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
663175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
663275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct i802_bss *bss = priv;
663375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
663475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen		   MAC2STR(bssid));
663575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	return nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, bssid, pmkid);
663675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
663775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
663875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
663975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinenstatic int nl80211_flush_pmkid(void *priv)
664075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen{
664175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	struct i802_bss *bss = priv;
664275ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs");
664375ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	return nl80211_pmkid(bss, NL80211_CMD_FLUSH_PMKSA, NULL, NULL);
664475ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen}
664575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
664675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen
66478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst struct wpa_driver_ops wpa_driver_nl80211_ops = {
66488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.name = "nl80211",
66498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.desc = "Linux nl80211/cfg80211",
66508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_bssid = wpa_driver_nl80211_get_bssid,
66518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_ssid = wpa_driver_nl80211_get_ssid,
66528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_key = wpa_driver_nl80211_set_key,
66538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.scan2 = wpa_driver_nl80211_scan,
66548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_scan_results2 = wpa_driver_nl80211_get_scan_results,
66558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.deauthenticate = wpa_driver_nl80211_deauthenticate,
66568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.disassociate = wpa_driver_nl80211_disassociate,
66578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.authenticate = wpa_driver_nl80211_authenticate,
66588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.associate = wpa_driver_nl80211_associate,
66598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.global_init = nl80211_global_init,
66608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.global_deinit = nl80211_global_deinit,
66618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.init2 = wpa_driver_nl80211_init,
66628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.deinit = wpa_driver_nl80211_deinit,
66638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_capa = wpa_driver_nl80211_get_capa,
66648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_operstate = wpa_driver_nl80211_set_operstate,
66658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_supp_port = wpa_driver_nl80211_set_supp_port,
66668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_country = wpa_driver_nl80211_set_country,
66678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_beacon = wpa_driver_nl80211_set_beacon,
66688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.if_add = wpa_driver_nl80211_if_add,
66698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.if_remove = wpa_driver_nl80211_if_remove,
66708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.send_mlme = wpa_driver_nl80211_send_mlme,
66718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
66728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.sta_add = wpa_driver_nl80211_sta_add,
66738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.sta_remove = wpa_driver_nl80211_sta_remove,
66748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
66758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.sta_set_flags = wpa_driver_nl80211_sta_set_flags,
66768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef HOSTAPD
66778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.hapd_init = i802_init,
66788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.hapd_deinit = i802_deinit,
667975ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	.set_wds_sta = i802_set_wds_sta,
668075ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen#endif /* HOSTAPD */
668175ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen#if defined(HOSTAPD) || defined(CONFIG_AP)
66828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_seqnum = i802_get_seqnum,
66838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.flush = i802_flush,
66848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.read_sta_data = i802_read_sta_data,
66858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_inact_sec = i802_get_inact_sec,
66868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.sta_clear_stats = i802_sta_clear_stats,
66878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_rts = i802_set_rts,
66888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_frag = i802_set_frag,
66898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_cts_protect = i802_set_cts_protect,
66908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_preamble = i802_set_preamble,
66918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_short_slot_time = i802_set_short_slot_time,
66928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_tx_queue_params = i802_set_tx_queue_params,
66938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_sta_vlan = i802_set_sta_vlan,
66948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_ht_params = i802_set_ht_params,
669575ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	.set_rate_sets = i802_set_rate_sets,
66968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.sta_deauth = i802_sta_deauth,
66978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.sta_disassoc = i802_sta_disassoc,
66988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* HOSTAPD || CONFIG_AP */
66998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_freq = i802_set_freq,
67008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.send_action = wpa_driver_nl80211_send_action,
67018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
67028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.remain_on_channel = wpa_driver_nl80211_remain_on_channel,
67038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.cancel_remain_on_channel =
67048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_driver_nl80211_cancel_remain_on_channel,
67058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.probe_req_report = wpa_driver_nl80211_probe_req_report,
67068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.disable_11b_rates = wpa_driver_nl80211_disable_11b_rates,
67078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.deinit_ap = wpa_driver_nl80211_deinit_ap,
67088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.resume = wpa_driver_nl80211_resume,
67098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.send_ft_action = nl80211_send_ft_action,
67108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.signal_monitor = nl80211_signal_monitor,
67118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.signal_poll = nl80211_signal_poll,
67128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.send_frame = nl80211_send_frame,
67138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_intra_bss = nl80211_set_intra_bss,
67148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.set_param = nl80211_set_param,
67158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	.get_radio_name = nl80211_get_radio_name,
671675ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	.add_pmkid = nl80211_add_pmkid,
671775ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	.remove_pmkid = nl80211_remove_pmkid,
671875ecf5267604f166b85a7ee2cf0d9cb682966680Jouni Malinen	.flush_pmkid = nl80211_flush_pmkid,
6719738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidt#ifdef ANDROID
6720738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidt	.driver_cmd = wpa_driver_nl80211_driver_cmd,
6721738a26e9e2087b0d43eba3534535632b27b49947Dmitry Shmidt#endif
67228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
6723