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