aboutsummaryrefslogtreecommitdiff
path: root/src/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/driver.h100
-rw-r--r--src/drivers/driver_atheros.c85
-rw-r--r--src/drivers/driver_bsd.c6
-rw-r--r--src/drivers/driver_hostap.c43
-rw-r--r--src/drivers/driver_hostap.h2
-rw-r--r--src/drivers/driver_ndis.c8
-rw-r--r--src/drivers/driver_nl80211.c455
-rw-r--r--src/drivers/driver_nl80211.h9
-rw-r--r--src/drivers/driver_nl80211_android.c34
-rw-r--r--src/drivers/driver_nl80211_capa.c90
-rw-r--r--src/drivers/driver_nl80211_event.c63
-rw-r--r--src/drivers/driver_nl80211_scan.c10
-rw-r--r--src/drivers/driver_privsep.c94
-rw-r--r--src/drivers/driver_wext.c133
-rw-r--r--src/drivers/drivers.c2
-rw-r--r--src/drivers/drivers.mak4
-rw-r--r--src/drivers/linux_ioctl.c23
-rw-r--r--src/drivers/linux_ioctl.h1
-rw-r--r--src/drivers/nl80211_copy.h236
19 files changed, 1112 insertions, 286 deletions
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 03bd1a79a14c0..3cdab5a7a87d6 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -20,6 +20,7 @@
#define WPA_SUPPLICANT_DRIVER_VERSION 4
#include "common/defs.h"
+#include "common/ieee802_11_defs.h"
#include "utils/list.h"
#define HOSTAPD_CHAN_DISABLED 0x00000001
@@ -341,7 +342,7 @@ struct wpa_driver_scan_params {
* is not needed anymore.
*/
struct wpa_driver_scan_filter {
- u8 ssid[32];
+ u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
} *filter_ssids;
@@ -1211,6 +1212,8 @@ struct wpa_driver_capa {
#define WPA_DRIVER_FLAGS_HT_IBSS 0x0000001000000000ULL
/** Driver supports IBSS with VHT datarates */
#define WPA_DRIVER_FLAGS_VHT_IBSS 0x0000002000000000ULL
+/** Driver supports automatic band selection */
+#define WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY 0x0000004000000000ULL
u64 flags;
#define WPA_DRIVER_SMPS_MODE_STATIC 0x00000001
@@ -1294,6 +1297,13 @@ struct wpa_driver_capa {
*/
#define WPA_DRIVER_FLAGS_TX_POWER_INSERTION 0x00000008
u32 rrm_flags;
+
+ /* Driver concurrency capabilities */
+ unsigned int conc_capab;
+ /* Maximum number of concurrent channels on 2.4 GHz */
+ unsigned int max_conc_chan_2_4;
+ /* Maximum number of concurrent channels on 5 GHz */
+ unsigned int max_conc_chan_5_0;
};
@@ -1394,6 +1404,16 @@ enum wpa_driver_if_type {
* WPA_IF_MESH - Mesh interface
*/
WPA_IF_MESH,
+
+ /*
+ * WPA_IF_TDLS - TDLS offchannel interface (used for pref freq only)
+ */
+ WPA_IF_TDLS,
+
+ /*
+ * WPA_IF_IBSS - IBSS interface (used for pref freq only)
+ */
+ WPA_IF_IBSS,
};
struct wpa_init_params {
@@ -1477,6 +1497,7 @@ struct wpa_signal_info {
int above_threshold;
int current_signal;
int avg_signal;
+ int avg_beacon_signal;
int current_noise;
int current_txrate;
enum chan_width chanwidth;
@@ -1576,6 +1597,7 @@ enum drv_br_port_attr {
enum drv_br_net_param {
DRV_BR_NET_PARAM_GARP_ACCEPT,
+ DRV_BR_MULTICAST_SNOOPING,
};
struct drv_acs_params {
@@ -1587,6 +1609,17 @@ struct drv_acs_params {
/* Indicates whether HT40 is enabled */
int ht40_enabled;
+
+ /* Indicates whether VHT is enabled */
+ int vht_enabled;
+
+ /* Configured ACS channel width */
+ u16 ch_width;
+
+ /* ACS channel list info */
+ unsigned int ch_list_len;
+ const u8 *ch_list;
+ const int *freq_list;
};
@@ -1925,10 +1958,12 @@ struct wpa_driver_ops {
* @data: IEEE 802.11 management frame with IEEE 802.11 header
* @data_len: Size of the management frame
* @noack: Do not wait for this frame to be acked (disable retries)
+ * @freq: Frequency (in MHz) to send the frame on, or 0 to let the
+ * driver decide
* Returns: 0 on success, -1 on failure
*/
int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
- int noack);
+ int noack, unsigned int freq);
/**
* update_ft_ies - Update FT (IEEE 802.11r) IEs
@@ -2332,7 +2367,8 @@ struct wpa_driver_ops {
* Returns: 0 on success, -1 on failure
*/
int (*sta_set_flags)(void *priv, const u8 *addr,
- int total_flags, int flags_or, int flags_and);
+ unsigned int total_flags, unsigned int flags_or,
+ unsigned int flags_and);
/**
* set_tx_queue_params - Set TX queue parameters
@@ -2656,18 +2692,6 @@ struct wpa_driver_ops {
int encrypt);
/**
- * shared_freq - Get operating frequency of shared interface(s)
- * @priv: Private driver interface data
- * Returns: Operating frequency in MHz, 0 if no shared operation in
- * use, or -1 on failure
- *
- * This command can be used to request the current operating frequency
- * of any virtual interface that shares the same radio to provide
- * information for channel selection for other virtual interfaces.
- */
- int (*shared_freq)(void *priv);
-
- /**
* get_noa - Get current Notice of Absence attribute payload
* @priv: Private driver interface data
* @buf: Buffer for returning NoA
@@ -3381,6 +3405,40 @@ struct wpa_driver_ops {
* indicates support for such offloading (WPA_DRIVER_FLAGS_ACS_OFFLOAD).
*/
int (*do_acs)(void *priv, struct drv_acs_params *params);
+
+ /**
+ * set_band - Notify driver of band selection
+ * @priv: Private driver interface data
+ * @band: The selected band(s)
+ * Returns 0 on success, -1 on failure
+ */
+ int (*set_band)(void *priv, enum set_band band);
+
+ /**
+ * get_pref_freq_list - Get preferred frequency list for an interface
+ * @priv: Private driver interface data
+ * @if_type: Interface type
+ * @num: Number of channels
+ * @freq_list: Preferred channel frequency list encoded in MHz values
+ * Returns 0 on success, -1 on failure
+ *
+ * This command can be used to query the preferred frequency list from
+ * the driver specific to a particular interface type.
+ */
+ int (*get_pref_freq_list)(void *priv, enum wpa_driver_if_type if_type,
+ unsigned int *num, unsigned int *freq_list);
+
+ /**
+ * set_prob_oper_freq - Indicate probable P2P operating channel
+ * @priv: Private driver interface data
+ * @freq: Channel frequency in MHz
+ * Returns 0 on success, -1 on failure
+ *
+ * This command can be used to inform the driver of the operating
+ * frequency that an ongoing P2P group formation is likely to come up
+ * on. Local device is assuming P2P Client role.
+ */
+ int (*set_prob_oper_freq)(void *priv, unsigned int freq);
};
@@ -4557,10 +4615,20 @@ union wpa_event_data {
* struct acs_selected_channels - Data for EVENT_ACS_CHANNEL_SELECTED
* @pri_channel: Selected primary channel
* @sec_channel: Selected secondary channel
+ * @vht_seg0_center_ch: VHT mode Segment0 center channel
+ * @vht_seg1_center_ch: VHT mode Segment1 center channel
+ * @ch_width: Selected Channel width by driver. Driver may choose to
+ * change hostapd configured ACS channel width due driver internal
+ * channel restrictions.
+ * hw_mode: Selected band (used with hw_mode=any)
*/
struct acs_selected_channels {
u8 pri_channel;
u8 sec_channel;
+ u8 vht_seg0_center_ch;
+ u8 vht_seg1_center_ch;
+ u16 ch_width;
+ enum hostapd_hw_mode hw_mode;
} acs_selected_channels;
};
@@ -4631,6 +4699,6 @@ wpa_get_wowlan_triggers(const char *wowlan_triggers,
const struct wpa_driver_capa *capa);
/* NULL terminated array of linked in driver wrappers */
-extern struct wpa_driver_ops *wpa_drivers[];
+extern const struct wpa_driver_ops *const wpa_drivers[];
#endif /* DRIVER_H */
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index f46442163d939..ef140934973af 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -55,6 +55,10 @@
#include "netlink.h"
#include "linux_ioctl.h"
+#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20) || defined(CONFIG_WNM) || defined(CONFIG_WPS)
+#define ATHEROS_USE_RAW_RECEIVE
+#endif
+
struct atheros_driver_data {
struct hostapd_data *hapd; /* back pointer */
@@ -430,7 +434,8 @@ atheros_set_sta_authorized(void *priv, const u8 *addr, int authorized)
static int
atheros_sta_set_flags(void *priv, const u8 *addr,
- int total_flags, int flags_or, int flags_and)
+ unsigned int total_flags, unsigned int flags_or,
+ unsigned int flags_and)
{
/* For now, only support setting Authorized flag */
if (flags_or & WPA_STA_AUTHORIZED)
@@ -823,7 +828,7 @@ static int atheros_set_qos_map(void *ctx, const u8 *qos_map_set,
return 0;
}
-#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_WNM) || defined(CONFIG_HS20)
+#ifdef ATHEROS_USE_RAW_RECEIVE
static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
size_t len)
{
@@ -911,7 +916,7 @@ static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
break;
}
}
-#endif
+#endif /* ATHEROS_USE_RAW_RECEIVE */
static int atheros_receive_pkt(struct atheros_driver_data *drv)
{
@@ -923,11 +928,11 @@ static int atheros_receive_pkt(struct atheros_driver_data *drv)
#ifdef CONFIG_WPS
filt.app_filterype |= IEEE80211_FILTER_TYPE_PROBE_REQ;
#endif /* CONFIG_WPS */
-#ifdef CONFIG_IEEE80211R
+#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R)
filt.app_filterype |= (IEEE80211_FILTER_TYPE_ASSOC_REQ |
IEEE80211_FILTER_TYPE_AUTH |
IEEE80211_FILTER_TYPE_ACTION);
-#endif
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
#ifdef CONFIG_WNM
filt.app_filterype |= IEEE80211_FILTER_TYPE_ACTION;
#endif /* CONFIG_WNM */
@@ -1026,7 +1031,7 @@ atheros_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
#define atheros_set_ap_wps_ie NULL
#endif /* CONFIG_WPS */
-#ifdef CONFIG_IEEE80211R
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
static int
atheros_sta_auth(void *priv, const u8 *own_addr, const u8 *addr, u16 seq,
u16 status_code, const u8 *ie, size_t len)
@@ -1102,7 +1107,7 @@ atheros_sta_assoc(void *priv, const u8 *own_addr, const u8 *addr,
}
return ret;
}
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
static void
atheros_new_sta(struct atheros_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
@@ -1177,6 +1182,7 @@ static void
atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
char *custom, char *end)
{
+#define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */
wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
@@ -1232,9 +1238,6 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
* so all are enabled for WPS... ugh.
*/
wpa_supplicant_event(drv->hapd, EVENT_WPS_BUTTON_PUSHED, NULL);
-#endif /* CONFIG_WPS */
-#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_HS20)
-#define MGMT_FRAM_TAG_SIZE 30 /* hardcoded in driver */
} else if (strncmp(custom, "Manage.prob_req ", 16) == 0) {
/*
* Atheros driver uses a hack to pass Probe Request frames as a
@@ -1250,40 +1253,46 @@ atheros_wireless_event_wireless_custom(struct atheros_driver_data *drv,
}
atheros_raw_receive(drv, NULL,
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
+#endif /* CONFIG_WPS */
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
} else if (strncmp(custom, "Manage.assoc_req ", 17) == 0) {
/* Format: "Manage.assoc_req <frame len>" | zero padding |
* frame */
int len = atoi(custom + 17);
if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
- wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
- "assoc_req/auth event length %d", len);
+ wpa_printf(MSG_DEBUG,
+ "Invalid Manage.assoc_req event length %d",
+ len);
return;
}
atheros_raw_receive(drv, NULL,
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
- } else if (strncmp(custom, "Manage.action ", 14) == 0) {
- /* Format: "Manage.assoc_req <frame len>" | zero padding |
- * frame */
- int len = atoi(custom + 14);
- if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
- wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
- "assoc_req/auth event length %d", len);
+ } else if (strncmp(custom, "Manage.auth ", 12) == 0) {
+ /* Format: "Manage.auth <frame len>" | zero padding | frame */
+ int len = atoi(custom + 12);
+ if (len < 0 ||
+ custom + MGMT_FRAM_TAG_SIZE + len > end) {
+ wpa_printf(MSG_DEBUG,
+ "Invalid Manage.auth event length %d", len);
return;
}
atheros_raw_receive(drv, NULL,
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
- } else if (strncmp(custom, "Manage.auth ", 12) == 0) {
- /* Format: "Manage.auth <frame len>" | zero padding | frame
+#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R */
+#ifdef ATHEROS_USE_RAW_RECEIVE
+ } else if (strncmp(custom, "Manage.action ", 14) == 0) {
+ /* Format: "Manage.assoc_req <frame len>" | zero padding | frame
*/
- int len = atoi(custom + 12);
+ int len = atoi(custom + 14);
if (len < 0 || custom + MGMT_FRAM_TAG_SIZE + len > end) {
- wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req/"
- "assoc_req/auth event length %d", len);
+ wpa_printf(MSG_DEBUG,
+ "Invalid Manage.action event length %d",
+ len);
return;
}
atheros_raw_receive(drv, NULL,
(u8 *) custom + MGMT_FRAM_TAG_SIZE, len);
-#endif /* CONFIG_WPS or CONFIG_IEEE80211R */
+#endif /* ATHEROS_USE_RAW_RECEIVE */
}
}
@@ -1682,8 +1691,7 @@ bad:
l2_packet_deinit(drv->sock_xmit);
if (drv->ioctl_sock >= 0)
close(drv->ioctl_sock);
- if (drv != NULL)
- free(drv);
+ os_free(drv);
return NULL;
}
@@ -1694,6 +1702,13 @@ atheros_deinit(void *priv)
struct atheros_driver_data *drv = priv;
atheros_reset_appfilter(drv);
+
+ if (drv->wpa_ie || drv->wps_beacon_ie || drv->wps_probe_resp_ie) {
+ wpabuf_free(drv->wpa_ie);
+ wpabuf_free(drv->wps_beacon_ie);
+ wpabuf_free(drv->wps_probe_resp_ie);
+ atheros_set_opt_ie(priv, NULL, 0);
+ }
netlink_deinit(drv->netlink);
(void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
if (drv->ioctl_sock >= 0)
@@ -1704,10 +1719,7 @@ atheros_deinit(void *priv)
l2_packet_deinit(drv->sock_xmit);
if (drv->sock_raw)
l2_packet_deinit(drv->sock_raw);
- wpabuf_free(drv->wpa_ie);
- wpabuf_free(drv->wps_beacon_ie);
- wpabuf_free(drv->wps_probe_resp_ie);
- free(drv);
+ os_free(drv);
}
static int
@@ -1833,10 +1845,10 @@ static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params)
}
-#ifdef CONFIG_IEEE80211R
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
- int noack)
+ int noack, unsigned int freq)
{
struct atheros_driver_data *drv = priv;
u8 buf[1510];
@@ -1858,8 +1870,11 @@ static int atheros_send_mgmt(void *priv, const u8 *frm, size_t data_len,
return set80211priv(drv, IEEE80211_IOCTL_SEND_MGMT, mgmt_frm,
sizeof(struct ieee80211req_mgmtbuf) + data_len);
}
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211R
+
static int atheros_add_tspec(void *priv, const u8 *addr, u8 *tspec_ie,
size_t tspec_ielen)
{
@@ -2139,10 +2154,12 @@ const struct wpa_driver_ops wpa_driver_atheros_ops = {
.set_ap_wps_ie = atheros_set_ap_wps_ie,
.set_authmode = atheros_set_authmode,
.set_ap = atheros_set_ap,
-#ifdef CONFIG_IEEE80211R
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
.sta_assoc = atheros_sta_assoc,
.sta_auth = atheros_sta_auth,
.send_mlme = atheros_send_mgmt,
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211R
.add_tspec = atheros_add_tspec,
.add_sta_node = atheros_add_sta_node,
#endif /* CONFIG_IEEE80211R */
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 0f1a0f60f27d6..bab1f031d24cd 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -861,8 +861,7 @@ bad:
if (drv->sock >= 0)
close(drv->sock);
os_free(drv->event_buf);
- if (drv != NULL)
- os_free(drv);
+ os_free(drv);
return NULL;
}
@@ -895,7 +894,8 @@ bsd_commit(void *priv)
static int
bsd_set_sta_authorized(void *priv, const u8 *addr,
- int total_flags, int flags_or, int flags_and)
+ unsigned int total_flags, unsigned int flags_or,
+ unsigned int flags_and)
{
int authorized = -1;
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index 84b98fb8c87f3..a7aa5eff00bd9 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -140,7 +140,7 @@ static void handle_tx_callback(struct hostap_driver_data *drv, u8 *buf,
static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len)
{
struct ieee80211_hdr *hdr;
- u16 fc, extra_len, type, stype;
+ u16 fc, type, stype;
size_t data_len = len;
int ver;
union wpa_event_data event;
@@ -165,19 +165,10 @@ static void handle_frame(struct hostap_driver_data *drv, u8 *buf, size_t len)
ver = fc & WLAN_FC_PVER;
- /* protocol version 3 is reserved for indicating extra data after the
- * payload, version 2 for indicating ACKed frame (TX callbacks), and
- * version 1 for indicating failed frame (no ACK, TX callbacks) */
- if (ver == 3) {
- u8 *pos = buf + len - 2;
- extra_len = WPA_GET_LE16(pos);
- printf("extra data in frame (elen=%d)\n", extra_len);
- if ((size_t) extra_len + 2 > len) {
- printf(" extra data overflow\n");
- return;
- }
- len -= extra_len + 2;
- } else if (ver == 1 || ver == 2) {
+ /* protocol version 2 is reserved for indicating ACKed frame (TX
+ * callbacks), and version 1 for indicating failed frame (no ACK, TX
+ * callbacks) */
+ if (ver == 1 || ver == 2) {
handle_tx_callback(drv, buf, data_len, ver == 2 ? 1 : 0);
return;
} else if (ver != 0) {
@@ -266,7 +257,8 @@ static int hostap_init_sockets(struct hostap_driver_data *drv, u8 *own_addr)
}
-static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack)
+static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack,
+ unsigned int freq)
{
struct hostap_driver_data *drv = priv;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg;
@@ -315,20 +307,21 @@ static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data,
pos += 2;
memcpy(pos, data, data_len);
- res = hostap_send_mlme(drv, (u8 *) hdr, len, 0);
+ res = hostap_send_mlme(drv, (u8 *) hdr, len, 0, 0);
if (res < 0) {
wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - "
"failed: %d (%s)",
(unsigned long) len, errno, strerror(errno));
}
- free(hdr);
+ os_free(hdr);
return res;
}
static int hostap_sta_set_flags(void *priv, const u8 *addr,
- int total_flags, int flags_or, int flags_and)
+ unsigned int total_flags, unsigned int flags_or,
+ unsigned int flags_and)
{
struct hostap_driver_data *drv = priv;
struct prism2_hostapd_param param;
@@ -470,18 +463,18 @@ static int hostap_get_seqnum(const char *ifname, void *priv, const u8 *addr,
param = (struct prism2_hostapd_param *) buf;
param->cmd = PRISM2_GET_ENCRYPTION;
if (addr == NULL)
- memset(param->sta_addr, 0xff, ETH_ALEN);
+ os_memset(param->sta_addr, 0xff, ETH_ALEN);
else
- memcpy(param->sta_addr, addr, ETH_ALEN);
+ os_memcpy(param->sta_addr, addr, ETH_ALEN);
param->u.crypt.idx = idx;
if (hostapd_ioctl(drv, param, blen)) {
printf("Failed to get encryption.\n");
ret = -1;
} else {
- memcpy(seq, param->u.crypt.seq, 8);
+ os_memcpy(seq, param->u.crypt.seq, 8);
}
- free(buf);
+ os_free(buf);
return ret;
}
@@ -1052,7 +1045,7 @@ static int hostap_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
memcpy(mgmt.bssid, own_addr, ETH_ALEN);
mgmt.u.deauth.reason_code = host_to_le16(reason);
return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
- sizeof(mgmt.u.deauth), 0);
+ sizeof(mgmt.u.deauth), 0, 0);
}
@@ -1090,7 +1083,7 @@ static int hostap_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
memcpy(mgmt.bssid, own_addr, ETH_ALEN);
mgmt.u.disassoc.reason_code = host_to_le16(reason);
return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
- sizeof(mgmt.u.disassoc), 0);
+ sizeof(mgmt.u.disassoc), 0, 0);
}
@@ -1168,7 +1161,7 @@ static void wpa_driver_hostap_poll_client(void *priv, const u8 *own_addr,
os_memcpy(hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
os_memcpy(hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
- hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0);
+ hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0, 0);
}
diff --git a/src/drivers/driver_hostap.h b/src/drivers/driver_hostap.h
index a9d3e76cbe8f3..4c1e6d69f0a7c 100644
--- a/src/drivers/driver_hostap.h
+++ b/src/drivers/driver_hostap.h
@@ -192,7 +192,7 @@ struct prism2_hostapd_param {
} mlme;
struct {
u8 ssid_len;
- u8 ssid[32];
+ u8 ssid[SSID_MAX_LEN];
} scan_req;
} u;
};
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index 4953af6a16b29..669f1b813c43f 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -709,11 +709,11 @@ static int wpa_driver_ndis_radio_off(struct wpa_driver_ndis_data *drv)
/* Disconnect by setting SSID to random (i.e., likely not used). */
static int wpa_driver_ndis_disconnect(struct wpa_driver_ndis_data *drv)
{
- char ssid[32];
+ char ssid[SSID_MAX_LEN];
int i;
- for (i = 0; i < 32; i++)
+ for (i = 0; i < SSID_MAX_LEN; i++)
ssid[i] = rand() & 0xff;
- return wpa_driver_ndis_set_ssid(drv, (u8 *) ssid, 32);
+ return wpa_driver_ndis_set_ssid(drv, (u8 *) ssid, SSID_MAX_LEN);
}
@@ -806,7 +806,7 @@ static struct wpa_scan_res * wpa_driver_ndis_add_scan_ssid(
if (wpa_scan_get_ie(r, WLAN_EID_SSID))
return r; /* SSID IE already present */
- if (ssid->SsidLength == 0 || ssid->SsidLength > 32)
+ if (ssid->SsidLength == 0 || ssid->SsidLength > SSID_MAX_LEN)
return r; /* No valid SSID inside scan data */
nr = os_realloc(r, sizeof(*r) + r->ie_len + 2 + ssid->SsidLength);
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index d7438683d8f01..00b173f3f85a3 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -87,7 +87,6 @@ static void nl80211_handle_destroy(struct nl_handle *handle)
#undef nl_socket_set_nonblocking
#define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h)
-#define genl_ctrl_resolve android_genl_ctrl_resolve
#endif /* ANDROID */
@@ -1187,6 +1186,7 @@ static int get_link_signal(struct nl_msg *msg, void *arg)
static struct nla_policy policy[NL80211_STA_INFO_MAX + 1] = {
[NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
[NL80211_STA_INFO_SIGNAL_AVG] = { .type = NLA_U8 },
+ [NL80211_STA_INFO_BEACON_SIGNAL_AVG] = { .type = NLA_U8 },
};
struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
@@ -1215,6 +1215,13 @@ static int get_link_signal(struct nl_msg *msg, void *arg)
else
sig_change->avg_signal = 0;
+ if (sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG])
+ sig_change->avg_beacon_signal =
+ (s8)
+ nla_get_u8(sinfo[NL80211_STA_INFO_BEACON_SIGNAL_AVG]);
+ else
+ sig_change->avg_beacon_signal = 0;
+
if (sinfo[NL80211_STA_INFO_TX_BITRATE]) {
if (nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
sinfo[NL80211_STA_INFO_TX_BITRATE],
@@ -1871,6 +1878,11 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
ret = -1;
}
#endif /* CONFIG_TDLS */
+#ifdef CONFIG_FST
+ /* FST Action frames */
+ if (nl80211_register_action_frame(bss, (u8 *) "\x12", 1) < 0)
+ ret = -1;
+#endif /* CONFIG_FST */
/* FT Action frames */
if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
@@ -2493,7 +2505,7 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
{
struct wpa_driver_nl80211_data *drv = bss->drv;
int ifindex;
- struct nl_msg *msg;
+ struct nl_msg *msg = NULL;
int ret;
int tdls = 0;
@@ -2526,11 +2538,15 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
if (!msg)
return -ENOBUFS;
} else {
+ u32 suite;
+
+ suite = wpa_alg_to_cipher_suite(alg, key_len);
+ if (!suite)
+ goto fail;
msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
if (!msg ||
nla_put(msg, NL80211_ATTR_KEY_DATA, key_len, key) ||
- nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER,
- wpa_alg_to_cipher_suite(alg, key_len)))
+ nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER, suite))
goto fail;
wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len);
}
@@ -2632,9 +2648,15 @@ static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
const u8 *key, size_t key_len)
{
struct nlattr *key_attr = nla_nest_start(msg, NL80211_ATTR_KEY);
+ u32 suite;
+
if (!key_attr)
return -1;
+ suite = wpa_alg_to_cipher_suite(alg, key_len);
+ if (!suite)
+ return -1;
+
if (defkey && alg == WPA_ALG_IGTK) {
if (nla_put_flag(msg, NL80211_KEY_DEFAULT_MGMT))
return -1;
@@ -2644,8 +2666,7 @@ static int nl_add_key(struct nl_msg *msg, enum wpa_alg alg,
}
if (nla_put_u8(msg, NL80211_KEY_IDX, key_idx) ||
- nla_put_u32(msg, NL80211_KEY_CIPHER,
- wpa_alg_to_cipher_suite(alg, key_len)) ||
+ nla_put_u32(msg, NL80211_KEY_CIPHER, suite) ||
(seq && seq_len &&
nla_put(msg, NL80211_KEY_SEQ, seq_len, seq)) ||
nla_put(msg, NL80211_KEY_DATA, key_len, key))
@@ -3237,7 +3258,7 @@ static int wpa_driver_nl80211_set_acl(void *priv,
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
struct nl_msg *msg;
- struct nlattr *acl;
+ struct nl_msg *acl;
unsigned int i;
int ret;
@@ -3250,23 +3271,26 @@ static int wpa_driver_nl80211_set_acl(void *priv,
wpa_printf(MSG_DEBUG, "nl80211: Set %s ACL (num_mac_acl=%u)",
params->acl_policy ? "Accept" : "Deny", params->num_mac_acl);
+ acl = nlmsg_alloc();
+ if (!acl)
+ return -ENOMEM;
+ for (i = 0; i < params->num_mac_acl; i++) {
+ if (nla_put(acl, i + 1, ETH_ALEN, params->mac_acl[i].addr)) {
+ nlmsg_free(acl);
+ return -ENOMEM;
+ }
+ }
+
if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MAC_ACL)) ||
nla_put_u32(msg, NL80211_ATTR_ACL_POLICY, params->acl_policy ?
NL80211_ACL_POLICY_DENY_UNLESS_LISTED :
NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED) ||
- (acl = nla_nest_start(msg, NL80211_ATTR_MAC_ADDRS)) == NULL) {
+ nla_put_nested(msg, NL80211_ATTR_MAC_ADDRS, acl)) {
nlmsg_free(msg);
+ nlmsg_free(acl);
return -ENOMEM;
}
-
- for (i = 0; i < params->num_mac_acl; i++) {
- if (nla_put(msg, i + 1, ETH_ALEN, params->mac_acl[i].addr)) {
- nlmsg_free(msg);
- return -ENOMEM;
- }
- }
-
- nla_nest_end(msg, acl);
+ nlmsg_free(acl);
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
@@ -4233,8 +4257,9 @@ static int wpa_driver_nl80211_hapd_send_eapol(
static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
- int total_flags,
- int flags_or, int flags_and)
+ unsigned int total_flags,
+ unsigned int flags_or,
+ unsigned int flags_and)
{
struct i802_bss *bss = priv;
struct nl_msg *msg;
@@ -5658,8 +5683,8 @@ static void *i802_init(struct hostapd_data *hapd,
struct wpa_driver_nl80211_data *drv;
struct i802_bss *bss;
size_t i;
- char brname[IFNAMSIZ];
- int ifindex, br_ifindex;
+ char master_ifname[IFNAMSIZ];
+ int ifindex, br_ifindex = 0;
int br_added = 0;
bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
@@ -5670,15 +5695,21 @@ static void *i802_init(struct hostapd_data *hapd,
drv = bss->drv;
- if (linux_br_get(brname, params->ifname) == 0) {
+ if (linux_br_get(master_ifname, params->ifname) == 0) {
wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
- params->ifname, brname);
- br_ifindex = if_nametoindex(brname);
- os_strlcpy(bss->brname, brname, IFNAMSIZ);
+ params->ifname, master_ifname);
+ br_ifindex = if_nametoindex(master_ifname);
+ os_strlcpy(bss->brname, master_ifname, IFNAMSIZ);
+ } else if ((params->num_bridge == 0 || !params->bridge[0]) &&
+ linux_master_get(master_ifname, params->ifname) == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in master %s",
+ params->ifname, master_ifname);
+ /* start listening for EAPOL on the master interface */
+ add_ifidx(drv, if_nametoindex(master_ifname));
} else {
- brname[0] = '\0';
- br_ifindex = 0;
+ master_ifname[0] = '\0';
}
+
bss->br_ifindex = br_ifindex;
for (i = 0; i < params->num_bridge; i++) {
@@ -5698,7 +5729,7 @@ static void *i802_init(struct hostapd_data *hapd,
if (i802_check_bridge(drv, bss, params->bridge[0],
params->ifname) < 0)
goto failed;
- if (os_strcmp(params->bridge[0], brname) != 0)
+ if (os_strcmp(params->bridge[0], master_ifname) != 0)
br_added = 1;
}
@@ -5776,13 +5807,12 @@ static enum nl80211_iftype wpa_driver_nl80211_if_type(
return NL80211_IFTYPE_P2P_DEVICE;
case WPA_IF_MESH:
return NL80211_IFTYPE_MESH_POINT;
+ default:
+ return -1;
}
- return -1;
}
-#if defined(CONFIG_P2P) || defined(CONFIG_MESH)
-
static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
{
struct wpa_driver_nl80211_data *drv;
@@ -5818,8 +5848,6 @@ static int nl80211_vif_addr(struct wpa_driver_nl80211_data *drv, u8 *new_addr)
return 0;
}
-#endif /* CONFIG_P2P || CONFIG_MESH */
-
struct wdev_info {
u64 wdev_id;
@@ -5895,21 +5923,21 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
}
if (!addr) {
- if (drv->nlmode == NL80211_IFTYPE_P2P_DEVICE)
+ if (nlmode == NL80211_IFTYPE_P2P_DEVICE)
os_memcpy(if_addr, bss->addr, ETH_ALEN);
else if (linux_get_ifhwaddr(drv->global->ioctl_sock,
- bss->ifname, if_addr) < 0) {
+ ifname, if_addr) < 0) {
if (added)
nl80211_remove_iface(drv, ifidx);
return -1;
}
}
-#if defined(CONFIG_P2P) || defined(CONFIG_MESH)
if (!addr &&
(type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
- type == WPA_IF_P2P_GO || type == WPA_IF_MESH)) {
- /* Enforce unique P2P Interface Address */
+ type == WPA_IF_P2P_GO || type == WPA_IF_MESH ||
+ type == WPA_IF_STATION)) {
+ /* Enforce unique address */
u8 new_addr[ETH_ALEN];
if (linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
@@ -5920,8 +5948,7 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
}
if (nl80211_addr_in_use(drv->global, new_addr)) {
wpa_printf(MSG_DEBUG, "nl80211: Allocate new address "
- "for %s interface", type == WPA_IF_MESH ?
- "mesh" : "P2P group");
+ "for interface %s type %d", ifname, type);
if (nl80211_vif_addr(drv, new_addr) < 0) {
if (added)
nl80211_remove_iface(drv, ifidx);
@@ -5936,7 +5963,6 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
}
os_memcpy(if_addr, new_addr, ETH_ALEN);
}
-#endif /* CONFIG_P2P || CONFIG_MESH */
if (type == WPA_IF_AP_BSS) {
struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
@@ -6514,47 +6540,6 @@ static int nl80211_signal_poll(void *priv, struct wpa_signal_info *si)
}
-static int wpa_driver_nl80211_shared_freq(void *priv)
-{
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- struct wpa_driver_nl80211_data *driver;
- int freq = 0;
-
- /*
- * If the same PHY is in connected state with some other interface,
- * then retrieve the assoc freq.
- */
- wpa_printf(MSG_DEBUG, "nl80211: Get shared freq for PHY %s",
- drv->phyname);
-
- dl_list_for_each(driver, &drv->global->interfaces,
- struct wpa_driver_nl80211_data, list) {
- if (drv == driver ||
- os_strcmp(drv->phyname, driver->phyname) != 0 ||
- !driver->associated)
- continue;
-
- wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s "
- MACSTR,
- driver->phyname, driver->first_bss->ifname,
- MAC2STR(driver->first_bss->addr));
- if (is_ap_interface(driver->nlmode))
- freq = driver->first_bss->freq;
- else
- freq = nl80211_get_assoc_freq(driver);
- wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
- drv->phyname, freq);
- }
-
- if (!freq)
- wpa_printf(MSG_DEBUG, "nl80211: No shared interface for "
- "PHY (%s) in associated state", drv->phyname);
-
- return freq;
-}
-
-
static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
int encrypt)
{
@@ -7275,11 +7260,12 @@ static int driver_nl80211_if_remove(void *priv, enum wpa_driver_if_type type,
static int driver_nl80211_send_mlme(void *priv, const u8 *data,
- size_t data_len, int noack)
+ size_t data_len, int noack,
+ unsigned int freq)
{
struct i802_bss *bss = priv;
return wpa_driver_nl80211_send_mlme(bss, data, data_len, noack,
- 0, 0, 0, 0);
+ freq, 0, 0, 0);
}
@@ -7506,7 +7492,10 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
"capa.max_acl_mac_addrs=%u\n"
"capa.num_multichan_concurrent=%u\n"
"capa.mac_addr_rand_sched_scan_supported=%d\n"
- "capa.mac_addr_rand_scan_supported=%d\n",
+ "capa.mac_addr_rand_scan_supported=%d\n"
+ "capa.conc_capab=%u\n"
+ "capa.max_conc_chan_2_4=%u\n"
+ "capa.max_conc_chan_5_0=%u\n",
drv->capa.key_mgmt,
drv->capa.enc,
drv->capa.auth,
@@ -7522,7 +7511,10 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen)
drv->capa.max_acl_mac_addrs,
drv->capa.num_multichan_concurrent,
drv->capa.mac_addr_rand_sched_scan_supported,
- drv->capa.mac_addr_rand_scan_supported);
+ drv->capa.mac_addr_rand_scan_supported,
+ drv->capa.conc_capab,
+ drv->capa.max_conc_chan_2_4,
+ drv->capa.max_conc_chan_5_0);
if (os_snprintf_error(end - pos, res))
return pos - buf;
pos += res;
@@ -7837,7 +7829,7 @@ static int nl80211_set_wowlan(void *priv,
wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan");
- if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WOWLAN)) ||
+ if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_SET_WOWLAN)) ||
!(wowlan_triggers = nla_nest_start(msg,
NL80211_ATTR_WOWLAN_TRIGGERS)) ||
(triggers->any &&
@@ -8340,9 +8332,9 @@ static const char * drv_br_net_param_str(enum drv_br_net_param param)
switch (param) {
case DRV_BR_NET_PARAM_GARP_ACCEPT:
return "arp_accept";
+ default:
+ return NULL;
}
-
- return NULL;
}
@@ -8354,6 +8346,13 @@ static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param,
const char *param_txt;
int ip_version = 4;
+ if (param == DRV_BR_MULTICAST_SNOOPING) {
+ os_snprintf(path, sizeof(path),
+ "/sys/devices/virtual/net/%s/bridge/multicast_snooping",
+ bss->brname);
+ goto set_val;
+ }
+
param_txt = drv_br_net_param_str(param);
if (param_txt == NULL)
return -EINVAL;
@@ -8369,6 +8368,7 @@ static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param,
os_snprintf(path, sizeof(path), "/proc/sys/net/ipv%d/conf/%s/%s",
ip_version, bss->brname, param_txt);
+set_val:
if (linux_write_system_file(path, val))
return -1;
@@ -8387,12 +8387,34 @@ static int hw_mode_to_qca_acs(enum hostapd_hw_mode hw_mode)
return QCA_ACS_MODE_IEEE80211A;
case HOSTAPD_MODE_IEEE80211AD:
return QCA_ACS_MODE_IEEE80211AD;
+ case HOSTAPD_MODE_IEEE80211ANY:
+ return QCA_ACS_MODE_IEEE80211ANY;
default:
return -1;
}
}
+static int add_acs_freq_list(struct nl_msg *msg, const int *freq_list)
+{
+ int i, len, ret;
+ u32 *freqs;
+
+ if (!freq_list)
+ return 0;
+ len = int_array_len(freq_list);
+ freqs = os_malloc(sizeof(u32) * len);
+ if (!freqs)
+ return -1;
+ for (i = 0; i < len; i++)
+ freqs[i] = freq_list[i];
+ ret = nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST,
+ sizeof(u32) * len, freqs);
+ os_free(freqs);
+ return ret;
+}
+
+
static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
{
struct i802_bss *bss = priv;
@@ -8415,12 +8437,25 @@ static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
(params->ht_enabled &&
nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED)) ||
(params->ht40_enabled &&
- nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED))) {
+ nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED)) ||
+ (params->vht_enabled &&
+ nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED)) ||
+ nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
+ params->ch_width) ||
+ (params->ch_list_len &&
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST, params->ch_list_len,
+ params->ch_list)) ||
+ add_acs_freq_list(msg, params->freq_list)) {
nlmsg_free(msg);
return -ENOBUFS;
}
nla_nest_end(msg, data);
+ wpa_printf(MSG_DEBUG,
+ "nl80211: ACS Params: HW_MODE: %d HT: %d HT40: %d VHT: %d BW: %d CH_LIST_LEN: %u",
+ params->hw_mode, params->ht_enabled, params->ht40_enabled,
+ params->vht_enabled, params->ch_width, params->ch_list_len);
+
ret = send_and_recv_msgs(drv, msg, NULL, NULL);
if (ret) {
wpa_printf(MSG_DEBUG,
@@ -8431,6 +8466,240 @@ static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
}
+static int nl80211_set_band(void *priv, enum set_band band)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *data;
+ int ret;
+ enum qca_set_band qca_band;
+
+ if (!drv->setband_vendor_cmd_avail)
+ return -1;
+
+ switch (band) {
+ case WPA_SETBAND_AUTO:
+ qca_band = QCA_SETBAND_AUTO;
+ break;
+ case WPA_SETBAND_5G:
+ qca_band = QCA_SETBAND_5G;
+ break;
+ case WPA_SETBAND_2G:
+ qca_band = QCA_SETBAND_2G;
+ break;
+ default:
+ return -1;
+ }
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_SETBAND) ||
+ !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE, qca_band)) {
+ nlmsg_free(msg);
+ return -ENOBUFS;
+ }
+ nla_nest_end(msg, data);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Driver setband function failed: %s",
+ strerror(errno));
+ }
+ return ret;
+}
+
+
+struct nl80211_pcl {
+ unsigned int num;
+ unsigned int *freq_list;
+};
+
+static int preferred_freq_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nl80211_pcl *param = arg;
+ struct nlattr *nl_vend, *attr;
+ enum qca_iface_type iface_type;
+ struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+ unsigned int num, max_num;
+ u32 *freqs;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
+ if (!nl_vend)
+ return NL_SKIP;
+
+ nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
+ nla_data(nl_vend), nla_len(nl_vend), NULL);
+
+ attr = tb_vendor[
+ QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE];
+ if (!attr) {
+ wpa_printf(MSG_ERROR, "nl80211: iface_type couldn't be found");
+ param->num = 0;
+ return NL_SKIP;
+ }
+
+ iface_type = (enum qca_iface_type) nla_get_u32(attr);
+ wpa_printf(MSG_DEBUG, "nl80211: Driver returned iface_type=%d",
+ iface_type);
+
+ attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST];
+ if (!attr) {
+ wpa_printf(MSG_ERROR,
+ "nl80211: preferred_freq_list couldn't be found");
+ param->num = 0;
+ return NL_SKIP;
+ }
+
+ /*
+ * param->num has the maximum number of entries for which there
+ * is room in the freq_list provided by the caller.
+ */
+ freqs = nla_data(attr);
+ max_num = nla_len(attr) / sizeof(u32);
+ if (max_num > param->num)
+ max_num = param->num;
+ for (num = 0; num < max_num; num++)
+ param->freq_list[num] = freqs[num];
+ param->num = num;
+
+ return NL_SKIP;
+}
+
+
+static int nl80211_get_pref_freq_list(void *priv,
+ enum wpa_driver_if_type if_type,
+ unsigned int *num,
+ unsigned int *freq_list)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+ unsigned int i;
+ struct nlattr *params;
+ struct nl80211_pcl param;
+ enum qca_iface_type iface_type;
+
+ if (!drv->get_pref_freq_list)
+ return -1;
+
+ switch (if_type) {
+ case WPA_IF_STATION:
+ iface_type = QCA_IFACE_TYPE_STA;
+ break;
+ case WPA_IF_AP_BSS:
+ iface_type = QCA_IFACE_TYPE_AP;
+ break;
+ case WPA_IF_P2P_GO:
+ iface_type = QCA_IFACE_TYPE_P2P_GO;
+ break;
+ case WPA_IF_P2P_CLIENT:
+ iface_type = QCA_IFACE_TYPE_P2P_CLIENT;
+ break;
+ case WPA_IF_IBSS:
+ iface_type = QCA_IFACE_TYPE_IBSS;
+ break;
+ case WPA_IF_TDLS:
+ iface_type = QCA_IFACE_TYPE_TDLS;
+ break;
+ default:
+ return -1;
+ }
+
+ param.num = *num;
+ param.freq_list = freq_list;
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_IFINDEX, drv->ifindex) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u32(msg,
+ QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE,
+ iface_type)) {
+ wpa_printf(MSG_ERROR,
+ "%s: err in adding vendor_cmd and vendor_data",
+ __func__);
+ nlmsg_free(msg);
+ return -1;
+ }
+ nla_nest_end(msg, params);
+
+ os_memset(freq_list, 0, *num * sizeof(freq_list[0]));
+ ret = send_and_recv_msgs(drv, msg, preferred_freq_info_handler, &param);
+ if (ret) {
+ wpa_printf(MSG_ERROR,
+ "%s: err in send_and_recv_msgs", __func__);
+ return ret;
+ }
+
+ *num = param.num;
+
+ for (i = 0; i < *num; i++) {
+ wpa_printf(MSG_DEBUG, "nl80211: preferred_channel_list[%d]=%d",
+ i, freq_list[i]);
+ }
+
+ return 0;
+}
+
+
+static int nl80211_set_prob_oper_freq(void *priv, unsigned int freq)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+ struct nlattr *params;
+
+ if (!drv->set_prob_oper_freq)
+ return -1;
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Set P2P probable operating freq %u for ifindex %d",
+ freq, bss->ifindex);
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ nla_put_u32(msg,
+ QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE,
+ QCA_IFACE_TYPE_P2P_CLIENT) ||
+ nla_put_u32(msg,
+ QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ,
+ freq)) {
+ wpa_printf(MSG_ERROR,
+ "%s: err in adding vendor_cmd and vendor_data",
+ __func__);
+ nlmsg_free(msg);
+ return -1;
+ }
+ nla_nest_end(msg, params);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_ERROR, "%s: err in send_and_recv_msgs",
+ __func__);
+ return ret;
+ }
+ nlmsg_free(msg);
+ return 0;
+}
+
+
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
@@ -8490,7 +8759,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.signal_monitor = nl80211_signal_monitor,
.signal_poll = nl80211_signal_poll,
.send_frame = nl80211_send_frame,
- .shared_freq = wpa_driver_nl80211_shared_freq,
.set_param = nl80211_set_param,
.get_radio_name = nl80211_get_radio_name,
.add_pmkid = nl80211_add_pmkid,
@@ -8518,7 +8786,9 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
#endif /* ANDROID_P2P */
#ifdef ANDROID
+#ifndef ANDROID_LIB_STUB
.driver_cmd = wpa_driver_nl80211_driver_cmd,
+#endif /* !ANDROID_LIB_STUB */
#endif /* ANDROID */
.vendor_cmd = nl80211_vendor_cmd,
.set_qos_map = nl80211_set_qos_map,
@@ -8537,4 +8807,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.add_tx_ts = nl80211_add_ts,
.del_tx_ts = nl80211_del_ts,
.do_acs = wpa_driver_do_acs,
+ .set_band = nl80211_set_band,
+ .get_pref_freq_list = nl80211_get_pref_freq_list,
+ .set_prob_oper_freq = nl80211_set_prob_oper_freq,
};
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 802589aa75812..5c21e0faf55cd 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -110,7 +110,7 @@ struct wpa_driver_nl80211_data {
u8 bssid[ETH_ALEN];
u8 prev_bssid[ETH_ALEN];
int associated;
- u8 ssid[32];
+ u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
enum nl80211_iftype nlmode;
enum nl80211_iftype ap_scan_as_station;
@@ -145,6 +145,9 @@ struct wpa_driver_nl80211_data {
unsigned int get_features_vendor_cmd_avail:1;
unsigned int set_rekey_offload:1;
unsigned int p2p_go_ctwindow_supported:1;
+ unsigned int setband_vendor_cmd_avail:1;
+ unsigned int get_pref_freq_list:1;
+ unsigned int set_prob_oper_freq:1;
u64 remain_on_chan_cookie;
u64 send_action_cookie;
@@ -169,7 +172,7 @@ struct wpa_driver_nl80211_data {
/* From failed authentication command */
int auth_freq;
u8 auth_bssid_[ETH_ALEN];
- u8 auth_ssid[32];
+ u8 auth_ssid[SSID_MAX_LEN];
size_t auth_ssid_len;
int auth_alg;
u8 *auth_ie;
@@ -232,7 +235,6 @@ int process_bss_event(struct nl_msg *msg, void *arg);
#ifdef ANDROID
int android_nl_socket_set_nonblocking(struct nl_handle *handle);
-int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name);
int android_pno_start(struct i802_bss *bss,
struct wpa_driver_scan_params *params);
int android_pno_stop(struct i802_bss *bss);
@@ -270,5 +272,6 @@ int wpa_driver_nl80211_sched_scan(void *priv,
int wpa_driver_nl80211_stop_sched_scan(void *priv);
struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv);
void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv);
+const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie);
#endif /* DRIVER_NL80211_H */
diff --git a/src/drivers/driver_nl80211_android.c b/src/drivers/driver_nl80211_android.c
index 3cc9a65867f64..ba47888843bbb 100644
--- a/src/drivers/driver_nl80211_android.c
+++ b/src/drivers/driver_nl80211_android.c
@@ -151,7 +151,7 @@ int android_pno_stop(struct i802_bss *bss)
#ifdef ANDROID_P2P
-#ifdef ANDROID_P2P_STUB
+#ifdef ANDROID_LIB_STUB
int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration)
{
@@ -178,7 +178,7 @@ int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
return 0;
}
-#endif /* ANDROID_P2P_STUB */
+#endif /* ANDROID_LIB_STUB */
#endif /* ANDROID_P2P */
@@ -188,33 +188,3 @@ int android_nl_socket_set_nonblocking(struct nl_handle *handle)
}
-int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name)
-{
- /*
- * Android ICS has very minimal genl_ctrl_resolve() implementation, so
- * need to work around that.
- */
- struct nl_cache *cache = NULL;
- struct genl_family *nl80211 = NULL;
- int id = -1;
-
- if (genl_ctrl_alloc_cache(handle, &cache) < 0) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
- "netlink cache");
- goto fail;
- }
-
- nl80211 = genl_ctrl_search_by_name(cache, name);
- if (nl80211 == NULL)
- goto fail;
-
- id = genl_family_get_id(nl80211);
-
-fail:
- if (nl80211)
- genl_family_put(nl80211);
- if (cache)
- nl_cache_free(cache);
-
- return id;
-}
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index e0d1d233e2ad5..4cf31238aeb70 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -335,6 +335,33 @@ static void wiphy_info_tdls(struct wpa_driver_capa *capa, struct nlattr *tdls,
}
+static int ext_feature_isset(const u8 *ext_features, int ext_features_len,
+ enum nl80211_ext_feature_index ftidx)
+{
+ u8 ft_byte;
+
+ if ((int) ftidx / 8 >= ext_features_len)
+ return 0;
+
+ ft_byte = ext_features[ftidx / 8];
+ return (ft_byte & BIT(ftidx % 8)) != 0;
+}
+
+
+static void wiphy_info_ext_feature_flags(struct wiphy_info_data *info,
+ struct nlattr *tb)
+{
+ struct wpa_driver_capa *capa = info->capa;
+
+ if (tb == NULL)
+ return;
+
+ if (ext_feature_isset(nla_data(tb), nla_len(tb),
+ NL80211_EXT_FEATURE_VHT_IBSS))
+ capa->flags |= WPA_DRIVER_FLAGS_VHT_IBSS;
+}
+
+
static void wiphy_info_feature_flags(struct wiphy_info_data *info,
struct nlattr *tb)
{
@@ -509,6 +536,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
info->device_ap_sme = 1;
wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]);
+ wiphy_info_ext_feature_flags(info, tb[NL80211_ATTR_EXT_FEATURES]);
wiphy_info_probe_resp_offload(capa,
tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
@@ -547,22 +575,34 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
continue;
}
vinfo = nla_data(nl);
- switch (vinfo->subcmd) {
- case QCA_NL80211_VENDOR_SUBCMD_TEST:
- drv->vendor_cmd_test_avail = 1;
- break;
- case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
- drv->roaming_vendor_cmd_avail = 1;
- break;
- case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
- drv->dfs_vendor_cmd_avail = 1;
- break;
- case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES:
- drv->get_features_vendor_cmd_avail = 1;
- break;
- case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
- drv->capa.flags |= WPA_DRIVER_FLAGS_ACS_OFFLOAD;
- break;
+ if (vinfo->vendor_id == OUI_QCA) {
+ switch (vinfo->subcmd) {
+ case QCA_NL80211_VENDOR_SUBCMD_TEST:
+ drv->vendor_cmd_test_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
+ drv->roaming_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
+ drv->dfs_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES:
+ drv->get_features_vendor_cmd_avail = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST:
+ drv->get_pref_freq_list = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL:
+ drv->set_prob_oper_freq = 1;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
+ drv->capa.flags |=
+ WPA_DRIVER_FLAGS_ACS_OFFLOAD;
+ break;
+ case QCA_NL80211_VENDOR_SUBCMD_SETBAND:
+ drv->setband_vendor_cmd_avail = 1;
+ break;
+ }
}
wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
@@ -717,6 +757,7 @@ static void qca_nl80211_check_dfs_capa(struct wpa_driver_nl80211_data *drv)
struct features_info {
u8 *flags;
size_t flags_len;
+ struct wpa_driver_capa *capa;
};
@@ -742,6 +783,19 @@ static int features_info_handler(struct nl_msg *msg, void *arg)
info->flags = nla_data(attr);
info->flags_len = nla_len(attr);
}
+ attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_CONCURRENCY_CAPA];
+ if (attr)
+ info->capa->conc_capab = nla_get_u32(attr);
+
+ attr = tb_vendor[
+ QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND];
+ if (attr)
+ info->capa->max_conc_chan_2_4 = nla_get_u32(attr);
+
+ attr = tb_vendor[
+ QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND];
+ if (attr)
+ info->capa->max_conc_chan_5_0 = nla_get_u32(attr);
}
return NL_SKIP;
@@ -776,12 +830,16 @@ static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv)
}
os_memset(&info, 0, sizeof(info));
+ info.capa = &drv->capa;
ret = send_and_recv_msgs(drv, msg, features_info_handler, &info);
if (ret || !info.flags)
return;
if (check_feature(QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD, &info))
drv->capa.flags |= WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD;
+
+ if (check_feature(QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY, &info))
+ drv->capa.flags |= WPA_DRIVER_FLAGS_SUPPORT_HW_MODE_ANY;
}
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 87e412dc596a5..7b0f721e65842 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -271,6 +271,7 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
struct nlattr *ptk_kek)
{
union wpa_event_data event;
+ const u8 *ssid;
u16 status_code;
if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
@@ -331,6 +332,16 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
if (req_ie) {
event.assoc_info.req_ies = nla_data(req_ie);
event.assoc_info.req_ies_len = nla_len(req_ie);
+
+ if (cmd == NL80211_CMD_ROAM) {
+ ssid = nl80211_get_ie(event.assoc_info.req_ies,
+ event.assoc_info.req_ies_len,
+ WLAN_EID_SSID);
+ if (ssid && ssid[1] > 0 && ssid[1] <= 32) {
+ drv->ssid_len = ssid[1];
+ os_memcpy(drv->ssid, ssid + 2, ssid[1]);
+ }
+ }
}
if (resp_ie) {
event.assoc_info.resp_ies = nla_data(resp_ie);
@@ -1480,6 +1491,25 @@ static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv,
}
+static enum hostapd_hw_mode get_qca_hw_mode(u8 hw_mode)
+{
+ switch (hw_mode) {
+ case QCA_ACS_MODE_IEEE80211B:
+ return HOSTAPD_MODE_IEEE80211B;
+ case QCA_ACS_MODE_IEEE80211G:
+ return HOSTAPD_MODE_IEEE80211G;
+ case QCA_ACS_MODE_IEEE80211A:
+ return HOSTAPD_MODE_IEEE80211A;
+ case QCA_ACS_MODE_IEEE80211AD:
+ return HOSTAPD_MODE_IEEE80211AD;
+ case QCA_ACS_MODE_IEEE80211ANY:
+ return HOSTAPD_MODE_IEEE80211ANY;
+ default:
+ return NUM_HOSTAPD_MODES;
+ }
+}
+
+
static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
const u8 *data, size_t len)
{
@@ -1500,6 +1530,39 @@ static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]);
event.acs_selected_channels.sec_channel =
nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]);
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
+ event.acs_selected_channels.vht_seg0_center_ch =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL]);
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL])
+ event.acs_selected_channels.vht_seg1_center_ch =
+ nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL]);
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH])
+ event.acs_selected_channels.ch_width =
+ nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]);
+ if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]) {
+ u8 hw_mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]);
+
+ event.acs_selected_channels.hw_mode = get_qca_hw_mode(hw_mode);
+ if (event.acs_selected_channels.hw_mode == NUM_HOSTAPD_MODES ||
+ event.acs_selected_channels.hw_mode ==
+ HOSTAPD_MODE_IEEE80211ANY) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Invalid hw_mode %d in ACS selection event",
+ hw_mode);
+ return;
+ }
+ }
+
+ wpa_printf(MSG_INFO,
+ "nl80211: ACS Results: PCH: %d SCH: %d BW: %d VHT0: %d VHT1: %d HW_MODE: %d",
+ event.acs_selected_channels.pri_channel,
+ event.acs_selected_channels.sec_channel,
+ event.acs_selected_channels.ch_width,
+ event.acs_selected_channels.vht_seg0_center_ch,
+ event.acs_selected_channels.vht_seg1_center_ch,
+ event.acs_selected_channels.hw_mode);
+
+ /* Ignore ACS channel list check for backwards compatibility */
wpa_supplicant_event(drv->ctx, EVENT_ACS_CHANNEL_SELECTED, &event);
}
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
index 3911f485f72e4..4b762eafbe8ae 100644
--- a/src/drivers/driver_nl80211_scan.c
+++ b/src/drivers/driver_nl80211_scan.c
@@ -221,6 +221,9 @@ int wpa_driver_nl80211_scan(struct i802_bss *bss,
wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
drv->scan_for_auth = 0;
+ if (TEST_FAIL())
+ return -1;
+
msg = nl80211_scan_common(bss, NL80211_CMD_TRIGGER_SCAN, params);
if (!msg)
return -1;
@@ -433,7 +436,7 @@ int wpa_driver_nl80211_stop_sched_scan(void *priv)
}
-static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
+const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
{
const u8 *end, *pos;
@@ -583,6 +586,11 @@ int bss_info_handler(struct nl_msg *msg, void *arg)
r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
if (bss[NL80211_BSS_TSF])
r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
+ if (bss[NL80211_BSS_BEACON_TSF]) {
+ u64 tsf = nla_get_u64(bss[NL80211_BSS_BEACON_TSF]);
+ if (tsf > r->tsf)
+ r->tsf = tsf;
+ }
if (bss[NL80211_BSS_SEEN_MS_AGO])
r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
r->ie_len = ie_len;
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index de23fbd2b9fe1..1f1676a20ac58 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -220,6 +220,56 @@ static int wpa_driver_privsep_set_key(const char *ifname, void *priv,
}
+static int wpa_driver_privsep_authenticate(
+ void *priv, struct wpa_driver_auth_params *params)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ struct privsep_cmd_authenticate *data;
+ int i, res;
+ size_t buflen;
+ u8 *pos;
+
+ wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d bssid=" MACSTR
+ " auth_alg=%d local_state_change=%d p2p=%d",
+ __func__, priv, params->freq, MAC2STR(params->bssid),
+ params->auth_alg, params->local_state_change, params->p2p);
+
+ buflen = sizeof(*data) + params->ie_len + params->sae_data_len;
+ data = os_zalloc(buflen);
+ if (data == NULL)
+ return -1;
+
+ data->freq = params->freq;
+ os_memcpy(data->bssid, params->bssid, ETH_ALEN);
+ os_memcpy(data->ssid, params->ssid, params->ssid_len);
+ data->ssid_len = params->ssid_len;
+ data->auth_alg = params->auth_alg;
+ data->ie_len = params->ie_len;
+ for (i = 0; i < 4; i++) {
+ if (params->wep_key[i])
+ os_memcpy(data->wep_key[i], params->wep_key[i],
+ params->wep_key_len[i]);
+ data->wep_key_len[i] = params->wep_key_len[i];
+ }
+ data->wep_tx_keyidx = params->wep_tx_keyidx;
+ data->local_state_change = params->local_state_change;
+ data->p2p = params->p2p;
+ pos = (u8 *) (data + 1);
+ if (params->ie_len) {
+ os_memcpy(pos, params->ie, params->ie_len);
+ pos += params->ie_len;
+ }
+ if (params->sae_data_len)
+ os_memcpy(pos, params->sae_data, params->sae_data_len);
+
+ res = wpa_priv_cmd(drv, PRIVSEP_CMD_AUTHENTICATE, data, buflen,
+ NULL, NULL);
+ os_free(data);
+
+ return res;
+}
+
+
static int wpa_driver_privsep_associate(
void *priv, struct wpa_driver_associate_params *params)
{
@@ -281,14 +331,15 @@ static int wpa_driver_privsep_get_ssid(void *priv, u8 *ssid)
{
struct wpa_driver_privsep_data *drv = priv;
int res, ssid_len;
- u8 reply[sizeof(int) + 32];
+ u8 reply[sizeof(int) + SSID_MAX_LEN];
size_t len = sizeof(reply);
res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SSID, NULL, 0, reply, &len);
if (res < 0 || len < sizeof(int))
return -1;
os_memcpy(&ssid_len, reply, sizeof(int));
- if (ssid_len < 0 || ssid_len > 32 || sizeof(int) + ssid_len > len) {
+ if (ssid_len < 0 || ssid_len > SSID_MAX_LEN ||
+ sizeof(int) + ssid_len > len) {
wpa_printf(MSG_DEBUG, "privsep: Invalid get SSID reply");
return -1;
}
@@ -308,6 +359,32 @@ static int wpa_driver_privsep_deauthenticate(void *priv, const u8 *addr,
}
+static void wpa_driver_privsep_event_auth(void *ctx, u8 *buf, size_t len)
+{
+ union wpa_event_data data;
+ struct privsep_event_auth *auth;
+
+ os_memset(&data, 0, sizeof(data));
+ if (len < sizeof(*auth))
+ return;
+ auth = (struct privsep_event_auth *) buf;
+ if (len < sizeof(*auth) + auth->ies_len)
+ return;
+
+ os_memcpy(data.auth.peer, auth->peer, ETH_ALEN);
+ os_memcpy(data.auth.bssid, auth->bssid, ETH_ALEN);
+ data.auth.auth_type = auth->auth_type;
+ data.auth.auth_transaction = auth->auth_transaction;
+ data.auth.status_code = auth->status_code;
+ if (auth->ies_len) {
+ data.auth.ies = (u8 *) (auth + 1);
+ data.auth.ies_len = auth->ies_len;
+ }
+
+ wpa_supplicant_event(ctx, EVENT_AUTH, &data);
+}
+
+
static void wpa_driver_privsep_event_assoc(void *ctx,
enum wpa_event_type event,
u8 *buf, size_t len)
@@ -467,6 +544,9 @@ static void wpa_driver_privsep_receive(int sock, void *eloop_ctx,
case PRIVSEP_EVENT_SCAN_RESULTS:
wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
break;
+ case PRIVSEP_EVENT_SCAN_STARTED:
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL);
+ break;
case PRIVSEP_EVENT_ASSOC:
wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOC,
event_buf, event_len);
@@ -502,6 +582,9 @@ static void wpa_driver_privsep_receive(int sock, void *eloop_ctx,
wpa_driver_privsep_event_rx_eapol(drv->ctx, event_buf,
event_len);
break;
+ case PRIVSEP_EVENT_AUTH:
+ wpa_driver_privsep_event_auth(drv->ctx, event_buf, event_len);
+ break;
}
os_free(buf);
@@ -702,6 +785,10 @@ static int wpa_driver_privsep_get_capa(void *priv,
res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_CAPA, NULL, 0, capa, &len);
if (res < 0 || len != sizeof(*capa))
return -1;
+ /* For now, no support for passing extended_capa pointers */
+ capa->extended_capa = NULL;
+ capa->extended_capa_mask = NULL;
+ capa->extended_capa_len = 0;
return 0;
}
@@ -734,6 +821,7 @@ struct wpa_driver_ops wpa_driver_privsep_ops = {
.set_param = wpa_driver_privsep_set_param,
.scan2 = wpa_driver_privsep_scan,
.deauthenticate = wpa_driver_privsep_deauthenticate,
+ .authenticate = wpa_driver_privsep_authenticate,
.associate = wpa_driver_privsep_associate,
.get_capa = wpa_driver_privsep_get_capa,
.get_mac_addr = wpa_driver_privsep_get_mac_addr,
@@ -742,7 +830,7 @@ struct wpa_driver_ops wpa_driver_privsep_ops = {
};
-struct wpa_driver_ops *wpa_drivers[] =
+const struct wpa_driver_ops *const wpa_drivers[] =
{
&wpa_driver_privsep_ops,
NULL
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index a1581b8c9cb1a..01defdff4f155 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -1,6 +1,6 @@
/*
* Driver interaction with generic Linux Wireless Extensions
- * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -18,6 +18,7 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <net/if_arp.h>
+#include <dirent.h>
#include "linux_wext.h"
#include "common.h"
@@ -131,7 +132,7 @@ int wpa_driver_wext_get_ssid(void *priv, u8 *ssid)
os_memset(&iwr, 0, sizeof(iwr));
os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
iwr.u.essid.pointer = (caddr_t) ssid;
- iwr.u.essid.length = 32;
+ iwr.u.essid.length = SSID_MAX_LEN;
if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
wpa_printf(MSG_ERROR, "ioctl[SIOCGIWESSID]: %s",
@@ -139,8 +140,8 @@ int wpa_driver_wext_get_ssid(void *priv, u8 *ssid)
ret = -1;
} else {
ret = iwr.u.essid.length;
- if (ret > 32)
- ret = 32;
+ if (ret > SSID_MAX_LEN)
+ ret = SSID_MAX_LEN;
/* Some drivers include nul termination in the SSID, so let's
* remove it here before further processing. WE-21 changes this
* to explicitly require the length _not_ to include nul
@@ -168,7 +169,7 @@ int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len)
int ret = 0;
char buf[33];
- if (ssid_len > 32)
+ if (ssid_len > SSID_MAX_LEN)
return -1;
os_memset(&iwr, 0, sizeof(iwr));
@@ -874,6 +875,105 @@ static void wpa_driver_wext_send_rfkill(void *eloop_ctx, void *timeout_ctx)
}
+static int wext_hostap_ifname(struct wpa_driver_wext_data *drv,
+ const char *ifname)
+{
+ char buf[200], *res;
+ int type;
+ FILE *f;
+
+ if (strcmp(ifname, ".") == 0 || strcmp(ifname, "..") == 0)
+ return -1;
+
+ snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net/%s/type",
+ drv->ifname, ifname);
+
+ f = fopen(buf, "r");
+ if (!f)
+ return -1;
+ res = fgets(buf, sizeof(buf), f);
+ fclose(f);
+
+ type = res ? atoi(res) : -1;
+ wpa_printf(MSG_DEBUG, "WEXT: hostap ifname %s type %d", ifname, type);
+
+ if (type == ARPHRD_IEEE80211) {
+ wpa_printf(MSG_DEBUG,
+ "WEXT: Found hostap driver wifi# interface (%s)",
+ ifname);
+ wpa_driver_wext_alternative_ifindex(drv, ifname);
+ return 0;
+ }
+ return -1;
+}
+
+
+static int wext_add_hostap(struct wpa_driver_wext_data *drv)
+{
+ char buf[200];
+ int n;
+ struct dirent **names;
+ int ret = -1;
+
+ snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/net", drv->ifname);
+ n = scandir(buf, &names, NULL, alphasort);
+ if (n < 0)
+ return -1;
+
+ while (n--) {
+ if (ret < 0 && wext_hostap_ifname(drv, names[n]->d_name) == 0)
+ ret = 0;
+ free(names[n]);
+ }
+ free(names);
+
+ return ret;
+}
+
+
+static void wext_check_hostap(struct wpa_driver_wext_data *drv)
+{
+ char buf[200], *pos;
+ ssize_t res;
+
+ /*
+ * Host AP driver may use both wlan# and wifi# interface in wireless
+ * events. Since some of the versions included WE-18 support, let's add
+ * the alternative ifindex also from driver_wext.c for the time being.
+ * This may be removed at some point once it is believed that old
+ * versions of the driver are not in use anymore. However, it looks like
+ * the wifi# interface is still used in the current kernel tree, so it
+ * may not really be possible to remove this before the Host AP driver
+ * gets removed from the kernel.
+ */
+
+ /* First, try to see if driver information is available from sysfs */
+ snprintf(buf, sizeof(buf), "/sys/class/net/%s/device/driver",
+ drv->ifname);
+ res = readlink(buf, buf, sizeof(buf) - 1);
+ if (res > 0) {
+ buf[res] = '\0';
+ pos = strrchr(buf, '/');
+ if (pos)
+ pos++;
+ else
+ pos = buf;
+ wpa_printf(MSG_DEBUG, "WEXT: Driver: %s", pos);
+ if (os_strncmp(pos, "hostap", 6) == 0 &&
+ wext_add_hostap(drv) == 0)
+ return;
+ }
+
+ /* Second, use the old design with hardcoded ifname */
+ if (os_strncmp(drv->ifname, "wlan", 4) == 0) {
+ char ifname2[IFNAMSIZ + 1];
+ os_strlcpy(ifname2, drv->ifname, sizeof(ifname2));
+ os_memcpy(ifname2, "wifi", 4);
+ wpa_driver_wext_alternative_ifindex(drv, ifname2);
+ }
+}
+
+
static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
{
int send_rfkill_event = 0;
@@ -914,20 +1014,7 @@ static int wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
drv->ifindex = if_nametoindex(drv->ifname);
- if (os_strncmp(drv->ifname, "wlan", 4) == 0) {
- /*
- * Host AP driver may use both wlan# and wifi# interface in
- * wireless events. Since some of the versions included WE-18
- * support, let's add the alternative ifindex also from
- * driver_wext.c for the time being. This may be removed at
- * some point once it is believed that old versions of the
- * driver are not in use anymore.
- */
- char ifname2[IFNAMSIZ + 1];
- os_strlcpy(ifname2, drv->ifname, sizeof(ifname2));
- os_memcpy(ifname2, "wifi", 4);
- wpa_driver_wext_alternative_ifindex(drv, ifname2);
- }
+ wext_check_hostap(drv);
netlink_send_oper_ifla(drv->netlink, drv->ifindex,
1, IF_OPER_DORMANT);
@@ -1112,7 +1199,7 @@ struct wext_scan_data {
struct wpa_scan_res res;
u8 *ie;
size_t ie_len;
- u8 ssid[32];
+ u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
int maxrate;
};
@@ -1865,7 +1952,7 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv)
{
struct iwreq iwr;
const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
- u8 ssid[32];
+ u8 ssid[SSID_MAX_LEN];
int i;
/*
@@ -1907,9 +1994,9 @@ static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv)
* SIOCSIWMLME commands (or tries to associate automatically
* after deauth/disassoc).
*/
- for (i = 0; i < 32; i++)
+ for (i = 0; i < SSID_MAX_LEN; i++)
ssid[i] = rand() & 0xFF;
- if (wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) {
+ if (wpa_driver_wext_set_ssid(drv, ssid, SSID_MAX_LEN) < 0) {
wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus "
"SSID to disconnect");
}
diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c
index f0c3bb3c63ba0..a98af9ac7d711 100644
--- a/src/drivers/drivers.c
+++ b/src/drivers/drivers.c
@@ -47,7 +47,7 @@ extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */
#endif /* CONFIG_DRIVER_NONE */
-struct wpa_driver_ops *wpa_drivers[] =
+const struct wpa_driver_ops *const wpa_drivers[] =
{
#ifdef CONFIG_DRIVER_NL80211
&wpa_driver_nl80211_ops,
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index 9434078757018..3dd43c73803e7 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -54,7 +54,9 @@ else
ifdef CONFIG_LIBNL_TINY
DRV_LIBS += -lnl-tiny
else
- DRV_LIBS += -lnl
+ ifndef CONFIG_OSX
+ DRV_LIBS += -lnl
+ endif
endif
ifdef CONFIG_LIBNL20
diff --git a/src/drivers/linux_ioctl.c b/src/drivers/linux_ioctl.c
index 837971d25c99e..e21147af1bcd6 100644
--- a/src/drivers/linux_ioctl.c
+++ b/src/drivers/linux_ioctl.c
@@ -219,3 +219,26 @@ int linux_br_get(char *brname, const char *ifname)
os_strlcpy(brname, pos, IFNAMSIZ);
return 0;
}
+
+
+int linux_master_get(char *master_ifname, const char *ifname)
+{
+ char buf[128], masterlink[128], *pos;
+ ssize_t res;
+
+ /* check whether there is a master */
+ os_snprintf(buf, sizeof(buf), "/sys/class/net/%s/master", ifname);
+
+ res = readlink(buf, masterlink, sizeof(masterlink));
+ if (res < 0 || (size_t) res >= sizeof(masterlink))
+ return -1;
+
+ masterlink[res] = '\0';
+
+ pos = os_strrchr(masterlink, '/');
+ if (pos == NULL)
+ return -1;
+ pos++;
+ os_strlcpy(master_ifname, pos, IFNAMSIZ);
+ return 0;
+}
diff --git a/src/drivers/linux_ioctl.h b/src/drivers/linux_ioctl.h
index c03fe6e9a3fd2..6de4d9b882751 100644
--- a/src/drivers/linux_ioctl.h
+++ b/src/drivers/linux_ioctl.h
@@ -18,5 +18,6 @@ int linux_br_del(int sock, const char *brname);
int linux_br_add_if(int sock, const char *brname, const char *ifname);
int linux_br_del_if(int sock, const char *brname, const char *ifname);
int linux_br_get(char *brname, const char *ifname);
+int linux_master_get(char *master_ifname, const char *ifname);
#endif /* LINUX_IOCTL_H */
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index b37bd5a1cb825..ae16ba9cb1e31 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -25,10 +25,30 @@
*
*/
+/*
+ * This header file defines the userspace API to the wireless stack. Please
+ * be careful not to break things - i.e. don't move anything around or so
+ * unless you can demonstrate that it breaks neither API nor ABI.
+ *
+ * Additions to the API should be accompanied by actual implementations in
+ * an upstream driver, so that example implementations exist in case there
+ * are ever concerns about the precise semantics of the API or changes are
+ * needed, and to ensure that code for dead (no longer implemented) API
+ * can actually be identified and removed.
+ * Nonetheless, semantics should also be documented carefully in this file.
+ */
+
#include <linux/types.h>
#define NL80211_GENL_NAME "nl80211"
+#define NL80211_MULTICAST_GROUP_CONFIG "config"
+#define NL80211_MULTICAST_GROUP_SCAN "scan"
+#define NL80211_MULTICAST_GROUP_REG "regulatory"
+#define NL80211_MULTICAST_GROUP_MLME "mlme"
+#define NL80211_MULTICAST_GROUP_VENDOR "vendor"
+#define NL80211_MULTICAST_GROUP_TESTMODE "testmode"
+
/**
* DOC: Station handling
*
@@ -173,8 +193,8 @@
* %NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME.
*
* @NL80211_CMD_GET_INTERFACE: Request an interface's configuration;
- * either a dump request on a %NL80211_ATTR_WIPHY or a specific get
- * on an %NL80211_ATTR_IFINDEX is supported.
+ * either a dump request for all interfaces or a specific get with a
+ * single %NL80211_ATTR_IFINDEX is supported.
* @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires
* %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
* @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response
@@ -252,7 +272,18 @@
* %NL80211_ATTR_IFINDEX.
*
* @NL80211_CMD_GET_REG: ask the wireless core to send us its currently set
- * regulatory domain.
+ * regulatory domain. If %NL80211_ATTR_WIPHY is specified and the device
+ * has a private regulatory domain, it will be returned. Otherwise, the
+ * global regdomain will be returned.
+ * A device will have a private regulatory domain if it uses the
+ * regulatory_hint() API. Even when a private regdomain is used the channel
+ * information will still be mended according to further hints from
+ * the regulatory core to help with compliance. A dump version of this API
+ * is now available which will returns the global regdomain as well as
+ * all private regdomains of present wiphys (for those that have it).
+ * If a wiphy is self-managed (%NL80211_ATTR_WIPHY_SELF_MANAGED_REG), then
+ * its private regdomain is the only valid one for it. The regulatory
+ * core is not used to help with compliance in this case.
* @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command
* after being queried by the kernel. CRDA replies by sending a regulatory
* domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our
@@ -306,7 +337,9 @@
* if passed, define which channels should be scanned; if not
* passed, all channels allowed for the current regulatory domain
* are used. Extra IEs can also be passed from the userspace by
- * using the %NL80211_ATTR_IE attribute.
+ * using the %NL80211_ATTR_IE attribute. The first cycle of the
+ * scheduled scan can be delayed by %NL80211_ATTR_SCHED_SCAN_DELAY
+ * is supplied.
* @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan. Returns -ENOENT if
* scheduled scan is not running. The caller may assume that as soon
* as the call returns, it is safe to start a new scheduled scan again.
@@ -774,6 +807,10 @@
* peer given by %NL80211_ATTR_MAC. Both peers must be on the base channel
* when this command completes.
*
+ * @NL80211_CMD_WIPHY_REG_CHANGE: Similar to %NL80211_CMD_REG_CHANGE, but used
+ * as an event to indicate changes for devices with wiphy-specific regdom
+ * management.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -958,6 +995,8 @@ enum nl80211_commands {
NL80211_CMD_TDLS_CHANNEL_SWITCH,
NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
+ NL80211_CMD_WIPHY_REG_CHANGE,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -1655,6 +1694,13 @@ enum nl80211_commands {
* @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface
* creation then the new interface will be owned by the netlink socket
* that created it and will be destroyed when the socket is closed.
+ * If set during scheduled scan start then the new scan req will be
+ * owned by the netlink socket that created it and the scheduled scan will
+ * be stopped when the socket is closed.
+ * If set during configuration of regulatory indoor operation then the
+ * regulatory indoor configuration would be owned by the netlink socket
+ * that configured the indoor setting, and the indoor operation would be
+ * cleared when the socket is closed.
*
* @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
* the TDLS link initiator.
@@ -1688,6 +1734,32 @@ enum nl80211_commands {
*
* @NL80211_ATTR_MAC_MASK: MAC address mask
*
+ * @NL80211_ATTR_WIPHY_SELF_MANAGED_REG: flag attribute indicating this device
+ * is self-managing its regulatory information and any regulatory domain
+ * obtained from it is coming from the device's wiphy and not the global
+ * cfg80211 regdomain.
+ *
+ * @NL80211_ATTR_EXT_FEATURES: extended feature flags contained in a byte
+ * array. The feature flags are identified by their bit index (see &enum
+ * nl80211_ext_feature_index). The bit index is ordered starting at the
+ * least-significant bit of the first byte in the array, ie. bit index 0
+ * is located at bit 0 of byte 0. bit index 25 would be located at bit 1
+ * of byte 3 (u8 array).
+ *
+ * @NL80211_ATTR_SURVEY_RADIO_STATS: Request overall radio statistics to be
+ * returned along with other survey data. If set, @NL80211_CMD_GET_SURVEY
+ * may return a survey entry without a channel indicating global radio
+ * statistics (only some values are valid and make sense.)
+ * For devices that don't return such an entry even then, the information
+ * should be contained in the result as the sum of the respective counters
+ * over all channels.
+ *
+ * @NL80211_ATTR_SCHED_SCAN_DELAY: delay before a scheduled scan (or a
+ * WoWLAN net-detect scan) is started, u32 in seconds.
+
+ * @NL80211_ATTR_REG_INDOOR: flag attribute, if set indicates that the device
+ * is operating in an indoor environment.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2045,6 +2117,18 @@ enum nl80211_attrs {
NL80211_ATTR_MAC_MASK,
+ NL80211_ATTR_WIPHY_SELF_MANAGED_REG,
+
+ NL80211_ATTR_EXT_FEATURES,
+
+ NL80211_ATTR_SURVEY_RADIO_STATS,
+
+ NL80211_ATTR_NETNS_FD,
+
+ NL80211_ATTR_SCHED_SCAN_DELAY,
+
+ NL80211_ATTR_REG_INDOOR,
+
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@@ -2085,7 +2169,7 @@ enum nl80211_attrs {
#define NL80211_MAX_SUPP_RATES 32
#define NL80211_MAX_SUPP_HT_RATES 77
-#define NL80211_MAX_SUPP_REG_RULES 32
+#define NL80211_MAX_SUPP_REG_RULES 64
#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0
#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16
#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24
@@ -2225,8 +2309,15 @@ struct nl80211_sta_flag_update {
* @NL80211_RATE_INFO_VHT_MCS: MCS index for VHT (u8)
* @NL80211_RATE_INFO_VHT_NSS: number of streams in VHT (u8)
* @NL80211_RATE_INFO_80_MHZ_WIDTH: 80 MHz VHT rate
- * @NL80211_RATE_INFO_80P80_MHZ_WIDTH: 80+80 MHz VHT rate
+ * @NL80211_RATE_INFO_80P80_MHZ_WIDTH: unused - 80+80 is treated the
+ * same as 160 for purposes of the bitrates
* @NL80211_RATE_INFO_160_MHZ_WIDTH: 160 MHz VHT rate
+ * @NL80211_RATE_INFO_10_MHZ_WIDTH: 10 MHz width - note that this is
+ * a legacy rate and will be reported as the actual bitrate, i.e.
+ * half the base (20 MHz) rate
+ * @NL80211_RATE_INFO_5_MHZ_WIDTH: 5 MHz width - note that this is
+ * a legacy rate and will be reported as the actual bitrate, i.e.
+ * a quarter of the base (20 MHz) rate
* @__NL80211_RATE_INFO_AFTER_LAST: internal use
*/
enum nl80211_rate_info {
@@ -2241,6 +2332,8 @@ enum nl80211_rate_info {
NL80211_RATE_INFO_80_MHZ_WIDTH,
NL80211_RATE_INFO_80P80_MHZ_WIDTH,
NL80211_RATE_INFO_160_MHZ_WIDTH,
+ NL80211_RATE_INFO_10_MHZ_WIDTH,
+ NL80211_RATE_INFO_5_MHZ_WIDTH,
/* keep last */
__NL80211_RATE_INFO_AFTER_LAST,
@@ -2285,18 +2378,24 @@ enum nl80211_sta_bss_param {
*
* @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved
* @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
- * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
- * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
- * @NL80211_STA_INFO_RX_BYTES64: total received bytes (u64, from this station)
- * @NL80211_STA_INFO_TX_BYTES64: total transmitted bytes (u64, to this station)
+ * @NL80211_STA_INFO_RX_BYTES: total received bytes (MPDU length)
+ * (u32, from this station)
+ * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (MPDU length)
+ * (u32, to this station)
+ * @NL80211_STA_INFO_RX_BYTES64: total received bytes (MPDU length)
+ * (u64, from this station)
+ * @NL80211_STA_INFO_TX_BYTES64: total transmitted bytes (MPDU length)
+ * (u64, to this station)
* @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
* @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
* containing info as possible, see &enum nl80211_rate_info
- * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station)
- * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this
- * station)
- * @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station)
- * @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station)
+ * @NL80211_STA_INFO_RX_PACKETS: total received packet (MSDUs and MMPDUs)
+ * (u32, from this station)
+ * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (MSDUs and MMPDUs)
+ * (u32, to this station)
+ * @NL80211_STA_INFO_TX_RETRIES: total retries (MPDUs) (u32, to this station)
+ * @NL80211_STA_INFO_TX_FAILED: total failed packets (MPDUs)
+ * (u32, to this station)
* @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm)
* @NL80211_STA_INFO_LLID: the station's mesh LLID
* @NL80211_STA_INFO_PLID: the station's mesh PLID
@@ -2320,6 +2419,16 @@ enum nl80211_sta_bss_param {
* Same format as NL80211_STA_INFO_CHAIN_SIGNAL.
* @NL80211_STA_EXPECTED_THROUGHPUT: expected throughput considering also the
* 802.11 header (u32, kbps)
+ * @NL80211_STA_INFO_RX_DROP_MISC: RX packets dropped for unspecified reasons
+ * (u64)
+ * @NL80211_STA_INFO_BEACON_RX: number of beacons received from this peer (u64)
+ * @NL80211_STA_INFO_BEACON_SIGNAL_AVG: signal strength average
+ * for beacons only (u8, dBm)
+ * @NL80211_STA_INFO_TID_STATS: per-TID statistics (see &enum nl80211_tid_stats)
+ * This is a nested attribute where each the inner attribute number is the
+ * TID+1 and the special TID 16 (i.e. value 17) is used for non-QoS frames;
+ * each one of those is again nested with &enum nl80211_tid_stats
+ * attributes carrying the actual values.
* @__NL80211_STA_INFO_AFTER_LAST: internal
* @NL80211_STA_INFO_MAX: highest possible station info attribute
*/
@@ -2352,6 +2461,10 @@ enum nl80211_sta_info {
NL80211_STA_INFO_CHAIN_SIGNAL,
NL80211_STA_INFO_CHAIN_SIGNAL_AVG,
NL80211_STA_INFO_EXPECTED_THROUGHPUT,
+ NL80211_STA_INFO_RX_DROP_MISC,
+ NL80211_STA_INFO_BEACON_RX,
+ NL80211_STA_INFO_BEACON_SIGNAL_AVG,
+ NL80211_STA_INFO_TID_STATS,
/* keep last */
__NL80211_STA_INFO_AFTER_LAST,
@@ -2359,6 +2472,31 @@ enum nl80211_sta_info {
};
/**
+ * enum nl80211_tid_stats - per TID statistics attributes
+ * @__NL80211_TID_STATS_INVALID: attribute number 0 is reserved
+ * @NL80211_TID_STATS_RX_MSDU: number of MSDUs received (u64)
+ * @NL80211_TID_STATS_TX_MSDU: number of MSDUs transmitted (or
+ * attempted to transmit; u64)
+ * @NL80211_TID_STATS_TX_MSDU_RETRIES: number of retries for
+ * transmitted MSDUs (not counting the first attempt; u64)
+ * @NL80211_TID_STATS_TX_MSDU_FAILED: number of failed transmitted
+ * MSDUs (u64)
+ * @NUM_NL80211_TID_STATS: number of attributes here
+ * @NL80211_TID_STATS_MAX: highest numbered attribute here
+ */
+enum nl80211_tid_stats {
+ __NL80211_TID_STATS_INVALID,
+ NL80211_TID_STATS_RX_MSDU,
+ NL80211_TID_STATS_TX_MSDU,
+ NL80211_TID_STATS_TX_MSDU_RETRIES,
+ NL80211_TID_STATS_TX_MSDU_FAILED,
+
+ /* keep last */
+ NUM_NL80211_TID_STATS,
+ NL80211_TID_STATS_MAX = NUM_NL80211_TID_STATS - 1
+};
+
+/**
* enum nl80211_mpath_flags - nl80211 mesh path flags
*
* @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active
@@ -2772,16 +2910,18 @@ enum nl80211_user_reg_hint_type {
* @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel
* @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm)
* @NL80211_SURVEY_INFO_IN_USE: channel is currently being used
- * @NL80211_SURVEY_INFO_CHANNEL_TIME: amount of time (in ms) that the radio
- * spent on this channel
- * @NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY: amount of the time the primary
+ * @NL80211_SURVEY_INFO_TIME: amount of time (in ms) that the radio
+ * was turned on (on channel or globally)
+ * @NL80211_SURVEY_INFO_TIME_BUSY: amount of the time the primary
* channel was sensed busy (either due to activity or energy detect)
- * @NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY: amount of time the extension
+ * @NL80211_SURVEY_INFO_TIME_EXT_BUSY: amount of time the extension
* channel was sensed busy
- * @NL80211_SURVEY_INFO_CHANNEL_TIME_RX: amount of time the radio spent
- * receiving data
- * @NL80211_SURVEY_INFO_CHANNEL_TIME_TX: amount of time the radio spent
- * transmitting data
+ * @NL80211_SURVEY_INFO_TIME_RX: amount of time the radio spent
+ * receiving data (on channel or globally)
+ * @NL80211_SURVEY_INFO_TIME_TX: amount of time the radio spent
+ * transmitting data (on channel or globally)
+ * @NL80211_SURVEY_INFO_TIME_SCAN: time the radio spent for scan
+ * (on this channel or globally)
* @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
* currently defined
* @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
@@ -2791,17 +2931,25 @@ enum nl80211_survey_info {
NL80211_SURVEY_INFO_FREQUENCY,
NL80211_SURVEY_INFO_NOISE,
NL80211_SURVEY_INFO_IN_USE,
- NL80211_SURVEY_INFO_CHANNEL_TIME,
- NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY,
- NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY,
- NL80211_SURVEY_INFO_CHANNEL_TIME_RX,
- NL80211_SURVEY_INFO_CHANNEL_TIME_TX,
+ NL80211_SURVEY_INFO_TIME,
+ NL80211_SURVEY_INFO_TIME_BUSY,
+ NL80211_SURVEY_INFO_TIME_EXT_BUSY,
+ NL80211_SURVEY_INFO_TIME_RX,
+ NL80211_SURVEY_INFO_TIME_TX,
+ NL80211_SURVEY_INFO_TIME_SCAN,
/* keep last */
__NL80211_SURVEY_INFO_AFTER_LAST,
NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1
};
+/* keep old names for compatibility */
+#define NL80211_SURVEY_INFO_CHANNEL_TIME NL80211_SURVEY_INFO_TIME
+#define NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY NL80211_SURVEY_INFO_TIME_BUSY
+#define NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY NL80211_SURVEY_INFO_TIME_EXT_BUSY
+#define NL80211_SURVEY_INFO_CHANNEL_TIME_RX NL80211_SURVEY_INFO_TIME_RX
+#define NL80211_SURVEY_INFO_CHANNEL_TIME_TX NL80211_SURVEY_INFO_TIME_TX
+
/**
* enum nl80211_mntr_flags - monitor configuration flags
*
@@ -2966,7 +3114,8 @@ enum nl80211_mesh_power_mode {
*
* @NL80211_MESHCONF_PLINK_TIMEOUT: If no tx activity is seen from a STA we've
* established peering with for longer than this time (in seconds), then
- * remove it from the STA's list of peers. Default is 30 minutes.
+ * remove it from the STA's list of peers. You may set this to 0 to disable
+ * the removal of the STA. Default is 30 minutes.
*
* @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
*/
@@ -3238,6 +3387,9 @@ enum nl80211_bss {
/**
* enum nl80211_bss_status - BSS "status"
* @NL80211_BSS_STATUS_AUTHENTICATED: Authenticated with this BSS.
+ * Note that this is no longer used since cfg80211 no longer
+ * keeps track of whether or not authentication was done with
+ * a given BSS.
* @NL80211_BSS_STATUS_ASSOCIATED: Associated with this BSS.
* @NL80211_BSS_STATUS_IBSS_JOINED: Joined to this IBSS.
*
@@ -3565,6 +3717,8 @@ struct nl80211_pattern_support {
* @NL80211_WOWLAN_TRIG_ANY: wake up on any activity, do not really put
* the chip into a special state -- works best with chips that have
* support for low-power operation already (flag)
+ * Note that this mode is incompatible with all of the others, if
+ * any others are even supported by the device.
* @NL80211_WOWLAN_TRIG_DISCONNECT: wake up on disconnect, the way disconnect
* is detected is implementation-specific (flag)
* @NL80211_WOWLAN_TRIG_MAGIC_PKT: wake up on magic packet (6x 0xff, followed
@@ -3621,9 +3775,12 @@ struct nl80211_pattern_support {
* @NL80211_WOWLAN_TRIG_NET_DETECT: wake up when a configured network
* is detected. This is a nested attribute that contains the
* same attributes used with @NL80211_CMD_START_SCHED_SCAN. It
- * specifies how the scan is performed (e.g. the interval and the
- * channels to scan) as well as the scan results that will
- * trigger a wake (i.e. the matchsets).
+ * specifies how the scan is performed (e.g. the interval, the
+ * channels to scan and the initial delay) as well as the scan
+ * results that will trigger a wake (i.e. the matchsets). This
+ * attribute is also sent in a response to
+ * @NL80211_CMD_GET_WIPHY, indicating the number of match sets
+ * supported by the driver (u32).
* @NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS: nested attribute
* containing an array with information about what triggered the
* wake up. If no elements are present in the array, it means
@@ -4194,6 +4351,21 @@ enum nl80211_feature_flags {
};
/**
+ * enum nl80211_ext_feature_index - bit index of extended features.
+ * @NL80211_EXT_FEATURE_VHT_IBSS: This driver supports IBSS with VHT datarates.
+ *
+ * @NUM_NL80211_EXT_FEATURES: number of extended features.
+ * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
+ */
+enum nl80211_ext_feature_index {
+ NL80211_EXT_FEATURE_VHT_IBSS,
+
+ /* add new features before the definition below */
+ NUM_NL80211_EXT_FEATURES,
+ MAX_NL80211_EXT_FEATURES = NUM_NL80211_EXT_FEATURES - 1
+};
+
+/**
* enum nl80211_probe_resp_offload_support_attr - optional supported
* protocols for probe-response offloading by the driver/FW.
* To be used with the %NL80211_ATTR_PROBE_RESP_OFFLOAD attribute.