Cumulative patch from commit bacb984b2d10c0dccb3b05b7779d5d4c5662e8b2
bacb984 radiotap: Update radiotap parser to library version
e9b32da Propagate scan failures over D-Bus
142817b Add a wpa_supplicant ctrl_iface event for regdom changes
150fd0b WPS: Split eapol_cb reconnect to a separate code path
ded4f94 WPS: Close p2p_group and temporary parameters to all network blocks
d6a36f3 nl80211: Mask out deauth even after own deauth request
e74dd0e Add forgotten ampdu_factor into wpa_supplicant.conf
759ff2f Re-enable use of wildcard SSID with passphrase
023b466 Fix a debug print to have a space between words
0cd8602 Add CTRL-EVENT-SIGNAL-CHANGE for bgscan signal update events
bd8838a Fix ctrl_iface BLACKLIST return value
Change-Id: I4099b6a33f062d2b6a74c995941a2c534df90b3e
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index cea4701..0e292e6 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -19,6 +19,13 @@
#define OUI_QCA 0x001374
/**
+ * enum qca_radiotap_vendor_ids - QCA radiotap vendor namespace IDs
+ */
+enum qca_radiotap_vendor_ids {
+ QCA_RADIOTAP_VID_WLANTEST = 0,
+};
+
+/**
* enum qca_nl80211_vendor_subcmds - QCA nl80211 vendor command identifiers
*
* @QCA_NL80211_VENDOR_SUBCMD_UNSPEC: Reserved value 0
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 7f39ccd..534bc99 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -64,6 +64,10 @@
#define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED "
/** A BSS entry was removed (followed by BSS entry id and BSSID) */
#define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED "
+/** Change in the signal level was reported by the driver */
+#define WPA_EVENT_SIGNAL_CHANGE "CTRL-EVENT-SIGNAL-CHANGE "
+/** Regulatory domain channel */
+#define WPA_EVENT_REGDOM_CHANGE "CTRL-EVENT-REGDOM-CHANGE "
/** RSN IBSS 4-way handshakes completed with specified peer */
#define IBSS_RSN_COMPLETED "IBSS-RSN-COMPLETED "
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 02ade12..13bf718 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -50,6 +50,14 @@
REGDOM_BEACON_HINT,
};
+enum reg_type {
+ REGDOM_TYPE_UNKNOWN,
+ REGDOM_TYPE_COUNTRY,
+ REGDOM_TYPE_WORLD,
+ REGDOM_TYPE_CUSTOM_WORLD,
+ REGDOM_TYPE_INTERSECTION,
+};
+
/**
* struct hostapd_channel_data - Channel information
*/
@@ -3851,9 +3859,13 @@
/**
* channel_list_changed - Data for EVENT_CHANNEL_LIST_CHANGED
* @initiator: Initiator of the regulatory change
+ * @type: Regulatory change type
+ * @alpha2: Country code (or "" if not available)
*/
struct channel_list_changed {
enum reg_change_initiator initiator;
+ enum reg_type type;
+ char alpha2[3];
} channel_list_changed;
/**
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index e531e22..7e3de51 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -297,6 +297,7 @@
unsigned int retry_auth:1;
unsigned int use_monitor:1;
unsigned int ignore_next_local_disconnect:1;
+ unsigned int ignore_next_local_deauth:1;
unsigned int allow_p2p_device:1;
unsigned int hostapd:1;
unsigned int start_mode_ap:1;
@@ -1836,6 +1837,14 @@
}
event.deauth_info.locally_generated =
!os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
+ if (drv->ignore_next_local_deauth) {
+ drv->ignore_next_local_deauth = 0;
+ if (event.deauth_info.locally_generated) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event triggered due to own deauth request");
+ return;
+ }
+ wpa_printf(MSG_WARNING, "nl80211: Was expecting local deauth but got another disconnect event first");
+ }
event.deauth_info.addr = bssid;
event.deauth_info.reason_code = reason_code;
if (frame + len > mgmt->u.deauth.variable) {
@@ -2880,6 +2889,69 @@
}
+static void nl80211_reg_change_event(struct wpa_driver_nl80211_data *drv,
+ struct nlattr *tb[])
+{
+ union wpa_event_data data;
+ enum nl80211_reg_initiator init;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
+
+ if (tb[NL80211_ATTR_REG_INITIATOR] == NULL)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ init = nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]);
+ wpa_printf(MSG_DEBUG, " * initiator=%d", init);
+ switch (init) {
+ case NL80211_REGDOM_SET_BY_CORE:
+ data.channel_list_changed.initiator = REGDOM_SET_BY_CORE;
+ break;
+ case NL80211_REGDOM_SET_BY_USER:
+ data.channel_list_changed.initiator = REGDOM_SET_BY_USER;
+ break;
+ case NL80211_REGDOM_SET_BY_DRIVER:
+ data.channel_list_changed.initiator = REGDOM_SET_BY_DRIVER;
+ break;
+ case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+ data.channel_list_changed.initiator = REGDOM_SET_BY_COUNTRY_IE;
+ break;
+ }
+
+ if (tb[NL80211_ATTR_REG_TYPE]) {
+ enum nl80211_reg_type type;
+ type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]);
+ wpa_printf(MSG_DEBUG, " * type=%d", type);
+ switch (type) {
+ case NL80211_REGDOM_TYPE_COUNTRY:
+ data.channel_list_changed.type = REGDOM_TYPE_COUNTRY;
+ break;
+ case NL80211_REGDOM_TYPE_WORLD:
+ data.channel_list_changed.type = REGDOM_TYPE_WORLD;
+ break;
+ case NL80211_REGDOM_TYPE_CUSTOM_WORLD:
+ data.channel_list_changed.type =
+ REGDOM_TYPE_CUSTOM_WORLD;
+ break;
+ case NL80211_REGDOM_TYPE_INTERSECTION:
+ data.channel_list_changed.type =
+ REGDOM_TYPE_INTERSECTION;
+ break;
+ }
+ }
+
+ if (tb[NL80211_ATTR_REG_ALPHA2]) {
+ os_strlcpy(data.channel_list_changed.alpha2,
+ nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]),
+ sizeof(data.channel_list_changed.alpha2));
+ wpa_printf(MSG_DEBUG, " * alpha2=%s",
+ data.channel_list_changed.alpha2);
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, &data);
+}
+
+
static void do_process_drv_event(struct i802_bss *bss, int cmd,
struct nlattr **tb)
{
@@ -2999,34 +3071,7 @@
nl80211_cqm_event(drv, tb);
break;
case NL80211_CMD_REG_CHANGE:
- wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
- if (tb[NL80211_ATTR_REG_INITIATOR] == NULL)
- break;
- os_memset(&data, 0, sizeof(data));
- switch (nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR])) {
- case NL80211_REGDOM_SET_BY_CORE:
- data.channel_list_changed.initiator =
- REGDOM_SET_BY_CORE;
- break;
- case NL80211_REGDOM_SET_BY_USER:
- data.channel_list_changed.initiator =
- REGDOM_SET_BY_USER;
- break;
- case NL80211_REGDOM_SET_BY_DRIVER:
- data.channel_list_changed.initiator =
- REGDOM_SET_BY_DRIVER;
- break;
- case NL80211_REGDOM_SET_BY_COUNTRY_IE:
- data.channel_list_changed.initiator =
- REGDOM_SET_BY_COUNTRY_IE;
- break;
- default:
- wpa_printf(MSG_DEBUG, "nl80211: Unknown reg change initiator %d received",
- nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]));
- break;
- }
- wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
- &data);
+ nl80211_reg_change_event(drv, tb);
break;
case NL80211_CMD_REG_BEACON_HINT:
wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
@@ -5878,6 +5923,7 @@
const u8 *addr, int reason_code)
{
struct wpa_driver_nl80211_data *drv = bss->drv;
+ int ret;
if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
nl80211_mark_disconnected(drv);
@@ -5888,8 +5934,14 @@
wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " reason_code=%d)",
__func__, MAC2STR(addr), reason_code);
nl80211_mark_disconnected(drv);
- return wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
- reason_code, 0);
+ ret = wpa_driver_nl80211_mlme(drv, addr, NL80211_CMD_DEAUTHENTICATE,
+ reason_code, 0);
+ /*
+ * For locally generated deauthenticate, supplicant already generates a
+ * DEAUTH event, so ignore the event from NL80211.
+ */
+ drv->ignore_next_local_deauth = ret == 0;
+ return ret;
}
@@ -7789,7 +7841,7 @@
return;
}
- if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) {
+ if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len, NULL)) {
wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame");
return;
}
@@ -7834,11 +7886,11 @@
return;
if (!injected)
- handle_frame(drv, buf + iter.max_length,
- len - iter.max_length, datarate, ssi_signal);
+ handle_frame(drv, buf + iter._max_length,
+ len - iter._max_length, datarate, ssi_signal);
else
- handle_tx_callback(drv->ctx, buf + iter.max_length,
- len - iter.max_length, !failed);
+ handle_tx_callback(drv->ctx, buf + iter._max_length,
+ len - iter._max_length, !failed);
}
@@ -11692,7 +11744,7 @@
"monitor_refcount=%d\n"
"last_mgmt_freq=%u\n"
"eapol_tx_sock=%d\n"
- "%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ "%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
drv->phyname,
drv->ifindex,
drv->operstate,
@@ -11726,6 +11778,8 @@
drv->use_monitor ? "use_monitor=1\n" : "",
drv->ignore_next_local_disconnect ?
"ignore_next_local_disconnect=1\n" : "",
+ drv->ignore_next_local_deauth ?
+ "ignore_next_local_deauth=1\n" : "",
drv->allow_p2p_device ? "allow_p2p_device=1\n" : "");
if (res < 0 || res >= end - pos)
return pos - buf;
diff --git a/src/utils/platform.h b/src/utils/platform.h
new file mode 100644
index 0000000..9ab734b
--- /dev/null
+++ b/src/utils/platform.h
@@ -0,0 +1,19 @@
+#include <stddef.h>
+#include <errno.h>
+#ifndef _BSD_SOURCE
+#define _BSD_SOURCE
+#endif
+#include <endian.h>
+
+#define le16_to_cpu le16toh
+#define le32_to_cpu le32toh
+#define get_unaligned(p) \
+({ \
+ struct packed_dummy_struct { \
+ typeof(*(p)) __val; \
+ } __attribute__((packed)) *__ptr = (void *) (p); \
+ \
+ __ptr->__val; \
+})
+#define get_unaligned_le16(p) le16_to_cpu(get_unaligned((uint16_t *)(p)))
+#define get_unaligned_le32(p) le32_to_cpu(get_unaligned((uint32_t *)(p)))
diff --git a/src/utils/radiotap.c b/src/utils/radiotap.c
index 804473f..197a4af 100644
--- a/src/utils/radiotap.c
+++ b/src/utils/radiotap.c
@@ -2,6 +2,7 @@
* Radiotap parser
*
* Copyright 2007 Andy Green <andy@warmcat.com>
+ * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -10,34 +11,44 @@
* Alternatively, this software may be distributed under the terms of BSD
* license.
*
- * See README and COPYING for more details.
- *
- *
- * Modified for userspace by Johannes Berg <johannes@sipsolutions.net>
- * I only modified some things on top to ease syncing should bugs be found.
+ * See COPYING for more details.
*/
-
-#include "includes.h"
-
-#include "common.h"
#include "radiotap_iter.h"
-
-#define le16_to_cpu le_to_host16
-#define le32_to_cpu le_to_host32
-#define __le32 uint32_t
-#define ulong unsigned long
-#define unlikely(cond) (cond)
-#define get_unaligned(p) \
-({ \
- struct packed_dummy_struct { \
- typeof(*(p)) __val; \
- } __attribute__((packed)) *__ptr = (void *) (p); \
- \
- __ptr->__val; \
-})
+#include "platform.h"
/* function prototypes and related defs are in radiotap_iter.h */
+static const struct radiotap_align_size rtap_namespace_sizes[] = {
+ [IEEE80211_RADIOTAP_TSFT] = { .align = 8, .size = 8, },
+ [IEEE80211_RADIOTAP_FLAGS] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_RATE] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_CHANNEL] = { .align = 2, .size = 4, },
+ [IEEE80211_RADIOTAP_FHSS] = { .align = 2, .size = 2, },
+ [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_DBM_ANTNOISE] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_LOCK_QUALITY] = { .align = 2, .size = 2, },
+ [IEEE80211_RADIOTAP_TX_ATTENUATION] = { .align = 2, .size = 2, },
+ [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = { .align = 2, .size = 2, },
+ [IEEE80211_RADIOTAP_DBM_TX_POWER] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_ANTENNA] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_DB_ANTNOISE] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_RX_FLAGS] = { .align = 2, .size = 2, },
+ [IEEE80211_RADIOTAP_TX_FLAGS] = { .align = 2, .size = 2, },
+ [IEEE80211_RADIOTAP_RTS_RETRIES] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, },
+ [IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, },
+ [IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, },
+ /*
+ * add more here as they are defined in radiotap.h
+ */
+};
+
+static const struct ieee80211_radiotap_namespace radiotap_ns = {
+ .n_bits = sizeof(rtap_namespace_sizes) / sizeof(rtap_namespace_sizes[0]),
+ .align_size = rtap_namespace_sizes,
+};
+
/**
* ieee80211_radiotap_iterator_init - radiotap parser iterator initialization
* @iterator: radiotap_iterator to initialize
@@ -73,38 +84,52 @@
* get_unaligned((type *)iterator.this_arg) to dereference
* iterator.this_arg for type "type" safely on all arches.
*
- * Example code:
- * See Documentation/networking/radiotap-headers.txt
+ * Example code: parse.c
*/
int ieee80211_radiotap_iterator_init(
- struct ieee80211_radiotap_iterator *iterator,
- struct ieee80211_radiotap_header *radiotap_header,
- int max_length)
+ struct ieee80211_radiotap_iterator *iterator,
+ struct ieee80211_radiotap_header *radiotap_header,
+ int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns)
{
+ /* must at least have the radiotap header */
+ if (max_length < (int)sizeof(struct ieee80211_radiotap_header))
+ return -EINVAL;
+
/* Linux only supports version 0 radiotap format */
if (radiotap_header->it_version)
return -EINVAL;
/* sanity check for allowed length and radiotap length field */
- if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len)))
+ if (max_length < get_unaligned_le16(&radiotap_header->it_len))
return -EINVAL;
- iterator->rtheader = radiotap_header;
- iterator->max_length = le16_to_cpu(get_unaligned(
- &radiotap_header->it_len));
- iterator->arg_index = 0;
- iterator->bitmap_shifter = le32_to_cpu(get_unaligned(
- &radiotap_header->it_present));
- iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header);
- iterator->this_arg = NULL;
+ iterator->_rtheader = radiotap_header;
+ iterator->_max_length = get_unaligned_le16(&radiotap_header->it_len);
+ iterator->_arg_index = 0;
+ iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present);
+ iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header);
+ iterator->_reset_on_ext = 0;
+ iterator->_next_bitmap = &radiotap_header->it_present;
+ iterator->_next_bitmap++;
+ iterator->_vns = vns;
+ iterator->current_namespace = &radiotap_ns;
+ iterator->is_radiotap_ns = 1;
+#ifdef RADIOTAP_SUPPORT_OVERRIDES
+ iterator->n_overrides = 0;
+ iterator->overrides = NULL;
+#endif
/* find payload start allowing for extended bitmap(s) */
- if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) {
- while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) &
- (1<<IEEE80211_RADIOTAP_EXT)) {
- iterator->arg += sizeof(u32);
+ if (iterator->_bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT)) {
+ if ((unsigned long)iterator->_arg -
+ (unsigned long)iterator->_rtheader + sizeof(uint32_t) >
+ (unsigned long)iterator->_max_length)
+ return -EINVAL;
+ while (get_unaligned_le32(iterator->_arg) &
+ (1 << IEEE80211_RADIOTAP_EXT)) {
+ iterator->_arg += sizeof(uint32_t);
/*
* check for insanity where the present bitmaps
@@ -112,12 +137,14 @@
* stated radiotap header length
*/
- if (((ulong)iterator->arg - (ulong)iterator->rtheader)
- > (ulong)iterator->max_length)
+ if ((unsigned long)iterator->_arg -
+ (unsigned long)iterator->_rtheader +
+ sizeof(uint32_t) >
+ (unsigned long)iterator->_max_length)
return -EINVAL;
}
- iterator->arg += sizeof(u32);
+ iterator->_arg += sizeof(uint32_t);
/*
* no need to check again for blowing past stated radiotap
@@ -126,11 +153,57 @@
*/
}
+ iterator->this_arg = iterator->_arg;
+
/* we are all initialized happily */
return 0;
}
+static void find_ns(struct ieee80211_radiotap_iterator *iterator,
+ uint32_t oui, uint8_t subns)
+{
+ int i;
+
+ iterator->current_namespace = NULL;
+
+ if (!iterator->_vns)
+ return;
+
+ for (i = 0; i < iterator->_vns->n_ns; i++) {
+ if (iterator->_vns->ns[i].oui != oui)
+ continue;
+ if (iterator->_vns->ns[i].subns != subns)
+ continue;
+
+ iterator->current_namespace = &iterator->_vns->ns[i];
+ break;
+ }
+}
+
+#ifdef RADIOTAP_SUPPORT_OVERRIDES
+static int find_override(struct ieee80211_radiotap_iterator *iterator,
+ int *align, int *size)
+{
+ int i;
+
+ if (!iterator->overrides)
+ return 0;
+
+ for (i = 0; i < iterator->n_overrides; i++) {
+ if (iterator->_arg_index == iterator->overrides[i].field) {
+ *align = iterator->overrides[i].align;
+ *size = iterator->overrides[i].size;
+ if (!*align) /* erroneous override */
+ return 0;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+#endif
+
/**
* ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
@@ -156,99 +229,106 @@
*/
int ieee80211_radiotap_iterator_next(
- struct ieee80211_radiotap_iterator *iterator)
+ struct ieee80211_radiotap_iterator *iterator)
{
-
- /*
- * small length lookup table for all radiotap types we heard of
- * starting from b0 in the bitmap, so we can walk the payload
- * area of the radiotap header
- *
- * There is a requirement to pad args, so that args
- * of a given length must begin at a boundary of that length
- * -- but note that compound args are allowed (eg, 2 x u16
- * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not
- * a reliable indicator of alignment requirement.
- *
- * upper nybble: content alignment for arg
- * lower nybble: content length for arg
- */
-
- static const u8 rt_sizes[] = {
- [IEEE80211_RADIOTAP_TSFT] = 0x88,
- [IEEE80211_RADIOTAP_FLAGS] = 0x11,
- [IEEE80211_RADIOTAP_RATE] = 0x11,
- [IEEE80211_RADIOTAP_CHANNEL] = 0x24,
- [IEEE80211_RADIOTAP_FHSS] = 0x22,
- [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11,
- [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11,
- [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22,
- [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22,
- [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22,
- [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11,
- [IEEE80211_RADIOTAP_ANTENNA] = 0x11,
- [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11,
- [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11,
- [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22,
- [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22,
- [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11,
- [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11,
- /*
- * add more here as they are defined in
- * include/net/ieee80211_radiotap.h
- */
- };
-
- /*
- * for every radiotap entry we can at
- * least skip (by knowing the length)...
- */
-
- while (iterator->arg_index < (int) sizeof(rt_sizes)) {
+ while (1) {
int hit = 0;
- int pad;
+ int pad, align, size, subns;
+ uint32_t oui;
- if (!(iterator->bitmap_shifter & 1))
+ /* if no more EXT bits, that's it */
+ if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT &&
+ !(iterator->_bitmap_shifter & 1))
+ return -ENOENT;
+
+ if (!(iterator->_bitmap_shifter & 1))
goto next_entry; /* arg not present */
+ /* get alignment/size of data */
+ switch (iterator->_arg_index % 32) {
+ case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE:
+ case IEEE80211_RADIOTAP_EXT:
+ align = 1;
+ size = 0;
+ break;
+ case IEEE80211_RADIOTAP_VENDOR_NAMESPACE:
+ align = 2;
+ size = 6;
+ break;
+ default:
+#ifdef RADIOTAP_SUPPORT_OVERRIDES
+ if (find_override(iterator, &align, &size)) {
+ /* all set */
+ } else
+#endif
+ if (!iterator->current_namespace ||
+ iterator->_arg_index >= iterator->current_namespace->n_bits) {
+ if (iterator->current_namespace == &radiotap_ns)
+ return -ENOENT;
+ align = 0;
+ } else {
+ align = iterator->current_namespace->align_size[iterator->_arg_index].align;
+ size = iterator->current_namespace->align_size[iterator->_arg_index].size;
+ }
+ if (!align) {
+ /* skip all subsequent data */
+ iterator->_arg = iterator->_next_ns_data;
+ /* give up on this namespace */
+ iterator->current_namespace = NULL;
+ goto next_entry;
+ }
+ break;
+ }
+
/*
* arg is present, account for alignment padding
- * 8-bit args can be at any alignment
- * 16-bit args must start on 16-bit boundary
- * 32-bit args must start on 32-bit boundary
- * 64-bit args must start on 64-bit boundary
*
- * note that total arg size can differ from alignment of
- * elements inside arg, so we use upper nybble of length
- * table to base alignment on
- *
- * also note: these alignments are ** relative to the
- * start of the radiotap header **. There is no guarantee
+ * Note that these alignments are relative to the start
+ * of the radiotap header. There is no guarantee
* that the radiotap header itself is aligned on any
* kind of boundary.
*
- * the above is why get_unaligned() is used to dereference
- * multibyte elements from the radiotap area
+ * The above is why get_unaligned() is used to dereference
+ * multibyte elements from the radiotap area.
*/
- pad = (((ulong)iterator->arg) -
- ((ulong)iterator->rtheader)) &
- ((rt_sizes[iterator->arg_index] >> 4) - 1);
+ pad = ((unsigned long)iterator->_arg -
+ (unsigned long)iterator->_rtheader) & (align - 1);
if (pad)
- iterator->arg +=
- (rt_sizes[iterator->arg_index] >> 4) - pad;
+ iterator->_arg += align - pad;
+
+ if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) {
+ int vnslen;
+
+ if ((unsigned long)iterator->_arg + size -
+ (unsigned long)iterator->_rtheader >
+ (unsigned long)iterator->_max_length)
+ return -EINVAL;
+
+ oui = (*iterator->_arg << 16) |
+ (*(iterator->_arg + 1) << 8) |
+ *(iterator->_arg + 2);
+ subns = *(iterator->_arg + 3);
+
+ find_ns(iterator, oui, subns);
+
+ vnslen = get_unaligned_le16(iterator->_arg + 4);
+ iterator->_next_ns_data = iterator->_arg + size + vnslen;
+ if (!iterator->current_namespace)
+ size += vnslen;
+ }
/*
* this is what we will return to user, but we need to
* move on first so next call has something fresh to test
*/
- iterator->this_arg_index = iterator->arg_index;
- iterator->this_arg = iterator->arg;
- hit = 1;
+ iterator->this_arg_index = iterator->_arg_index;
+ iterator->this_arg = iterator->_arg;
+ iterator->this_arg_size = size;
/* internally move on the size of this arg */
- iterator->arg += rt_sizes[iterator->arg_index] & 0x0f;
+ iterator->_arg += size;
/*
* check for insanity where we are given a bitmap that
@@ -257,31 +337,57 @@
* max_length on the last arg, never exceeding it.
*/
- if (((ulong)iterator->arg - (ulong)iterator->rtheader) >
- (ulong) iterator->max_length)
+ if ((unsigned long)iterator->_arg -
+ (unsigned long)iterator->_rtheader >
+ (unsigned long)iterator->_max_length)
return -EINVAL;
- next_entry:
- iterator->arg_index++;
- if (unlikely((iterator->arg_index & 31) == 0)) {
- /* completed current u32 bitmap */
- if (iterator->bitmap_shifter & 1) {
- /* b31 was set, there is more */
- /* move to next u32 bitmap */
- iterator->bitmap_shifter = le32_to_cpu(
- get_unaligned(iterator->next_bitmap));
- iterator->next_bitmap++;
- } else
- /* no more bitmaps: end */
- iterator->arg_index = sizeof(rt_sizes);
- } else /* just try the next bit */
- iterator->bitmap_shifter >>= 1;
+ /* these special ones are valid in each bitmap word */
+ switch (iterator->_arg_index % 32) {
+ case IEEE80211_RADIOTAP_VENDOR_NAMESPACE:
+ iterator->_reset_on_ext = 1;
+
+ iterator->is_radiotap_ns = 0;
+ /*
+ * If parser didn't register this vendor
+ * namespace with us, allow it to show it
+ * as 'raw. Do do that, set argument index
+ * to vendor namespace.
+ */
+ iterator->this_arg_index =
+ IEEE80211_RADIOTAP_VENDOR_NAMESPACE;
+ if (!iterator->current_namespace)
+ hit = 1;
+ goto next_entry;
+ case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE:
+ iterator->_reset_on_ext = 1;
+ iterator->current_namespace = &radiotap_ns;
+ iterator->is_radiotap_ns = 1;
+ goto next_entry;
+ case IEEE80211_RADIOTAP_EXT:
+ /*
+ * bit 31 was set, there is more
+ * -- move to next u32 bitmap
+ */
+ iterator->_bitmap_shifter =
+ get_unaligned_le32(iterator->_next_bitmap);
+ iterator->_next_bitmap++;
+ if (iterator->_reset_on_ext)
+ iterator->_arg_index = 0;
+ else
+ iterator->_arg_index++;
+ iterator->_reset_on_ext = 0;
+ break;
+ default:
+ /* we've got a hit! */
+ hit = 1;
+ next_entry:
+ iterator->_bitmap_shifter >>= 1;
+ iterator->_arg_index++;
+ }
/* if we found a valid arg earlier, return it now */
if (hit)
return 0;
}
-
- /* we don't know how to handle any more args, we're done */
- return -ENOENT;
}
diff --git a/src/utils/radiotap.h b/src/utils/radiotap.h
index 137288f..0572e7c 100644
--- a/src/utils/radiotap.h
+++ b/src/utils/radiotap.h
@@ -1,6 +1,3 @@
-/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */
-/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */
-
/*-
* Copyright (c) 2003, 2004 David Young. All rights reserved.
*
@@ -178,6 +175,14 @@
*
* Number of unicast retries a transmitted frame used.
*
+ * IEEE80211_RADIOTAP_MCS u8, u8, u8 unitless
+ *
+ * Contains a bitmap of known fields/flags, the flags, and
+ * the MCS index.
+ *
+ * IEEE80211_RADIOTAP_AMPDU_STATUS u32, u16, u8, u8 unitlesss
+ *
+ * Contains the AMPDU information for the subframe.
*/
enum ieee80211_radiotap_type {
IEEE80211_RADIOTAP_TSFT = 0,
@@ -198,6 +203,13 @@
IEEE80211_RADIOTAP_TX_FLAGS = 15,
IEEE80211_RADIOTAP_RTS_RETRIES = 16,
IEEE80211_RADIOTAP_DATA_RETRIES = 17,
+
+ IEEE80211_RADIOTAP_MCS = 19,
+ IEEE80211_RADIOTAP_AMPDU_STATUS = 20,
+
+ /* valid in every it_present bitmap, even vendor namespaces */
+ IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29,
+ IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30,
IEEE80211_RADIOTAP_EXT = 31
};
@@ -230,8 +242,10 @@
* 802.11 header and payload
* (to 32-bit boundary)
*/
+#define IEEE80211_RADIOTAP_F_BADFCS 0x40 /* frame failed FCS check */
+
/* For IEEE80211_RADIOTAP_RX_FLAGS */
-#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */
+#define IEEE80211_RADIOTAP_F_RX_BADPLCP 0x0002 /* bad PLCP */
/* For IEEE80211_RADIOTAP_TX_FLAGS */
#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive
@@ -240,4 +254,38 @@
#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
#define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008 /* don't expect an ACK */
+/* For IEEE80211_RADIOTAP_AMPDU_STATUS */
+#define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN 0x0001
+#define IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN 0x0002
+#define IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN 0x0004
+#define IEEE80211_RADIOTAP_AMPDU_IS_LAST 0x0008
+#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR 0x0010
+#define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN 0x0020
+
+/* For IEEE80211_RADIOTAP_MCS */
+#define IEEE80211_RADIOTAP_MCS_HAVE_BW 0x01
+#define IEEE80211_RADIOTAP_MCS_HAVE_MCS 0x02
+#define IEEE80211_RADIOTAP_MCS_HAVE_GI 0x04
+#define IEEE80211_RADIOTAP_MCS_HAVE_FMT 0x08
+#define IEEE80211_RADIOTAP_MCS_HAVE_FEC 0x10
+#define IEEE80211_RADIOTAP_MCS_HAVE_STBC 0x20
+#define IEEE80211_RADIOTAP_MCS_HAVE_NESS 0x40
+#define IEEE80211_RADIOTAP_MCS_NESS_BIT1 0x80
+
+
+#define IEEE80211_RADIOTAP_MCS_BW_MASK 0x03
+#define IEEE80211_RADIOTAP_MCS_BW_20 0
+#define IEEE80211_RADIOTAP_MCS_BW_40 1
+#define IEEE80211_RADIOTAP_MCS_BW_20L 2
+#define IEEE80211_RADIOTAP_MCS_BW_20U 3
+#define IEEE80211_RADIOTAP_MCS_SGI 0x04
+#define IEEE80211_RADIOTAP_MCS_FMT_GF 0x08
+#define IEEE80211_RADIOTAP_MCS_FEC_LDPC 0x10
+#define IEEE80211_RADIOTAP_MCS_STBC_MASK 0x60
+#define IEEE80211_RADIOTAP_MCS_STBC_SHIFT 5
+#define IEEE80211_RADIOTAP_MCS_STBC_1 1
+#define IEEE80211_RADIOTAP_MCS_STBC_2 2
+#define IEEE80211_RADIOTAP_MCS_STBC_3 3
+#define IEEE80211_RADIOTAP_MCS_NESS_BIT0 0x80
+
#endif /* IEEE80211_RADIOTAP_H */
diff --git a/src/utils/radiotap_iter.h b/src/utils/radiotap_iter.h
index 2e0e872..b768c85 100644
--- a/src/utils/radiotap_iter.h
+++ b/src/utils/radiotap_iter.h
@@ -1,56 +1,96 @@
-/*
- * Radiotap parser
- *
- * Copyright 2007 Andy Green <andy@warmcat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
#ifndef __RADIOTAP_ITER_H
#define __RADIOTAP_ITER_H
+#include <stdint.h>
#include "radiotap.h"
/* Radiotap header iteration
* implemented in radiotap.c
*/
+
+struct radiotap_override {
+ uint8_t field;
+ uint8_t align:4, size:4;
+};
+
+struct radiotap_align_size {
+ uint8_t align:4, size:4;
+};
+
+struct ieee80211_radiotap_namespace {
+ const struct radiotap_align_size *align_size;
+ int n_bits;
+ uint32_t oui;
+ uint8_t subns;
+};
+
+struct ieee80211_radiotap_vendor_namespaces {
+ const struct ieee80211_radiotap_namespace *ns;
+ int n_ns;
+};
+
/**
* struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args
- * @rtheader: pointer to the radiotap header we are walking through
- * @max_length: length of radiotap header in cpu byte ordering
- * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg
- * @this_arg: pointer to current radiotap arg
- * @arg_index: internal next argument index
- * @arg: internal next argument pointer
- * @next_bitmap: internal pointer to next present u32
- * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present
+ * @this_arg_index: index of current arg, valid after each successful call
+ * to ieee80211_radiotap_iterator_next()
+ * @this_arg: pointer to current radiotap arg; it is valid after each
+ * call to ieee80211_radiotap_iterator_next() but also after
+ * ieee80211_radiotap_iterator_init() where it will point to
+ * the beginning of the actual data portion
+ * @this_arg_size: length of the current arg, for convenience
+ * @current_namespace: pointer to the current namespace definition
+ * (or internally %NULL if the current namespace is unknown)
+ * @is_radiotap_ns: indicates whether the current namespace is the default
+ * radiotap namespace or not
+ *
+ * @overrides: override standard radiotap fields
+ * @n_overrides: number of overrides
+ *
+ * @_rtheader: pointer to the radiotap header we are walking through
+ * @_max_length: length of radiotap header in cpu byte ordering
+ * @_arg_index: next argument index
+ * @_arg: next argument pointer
+ * @_next_bitmap: internal pointer to next present u32
+ * @_bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present
+ * @_vns: vendor namespace definitions
+ * @_next_ns_data: beginning of the next namespace's data
+ * @_reset_on_ext: internal; reset the arg index to 0 when going to the
+ * next bitmap word
+ *
+ * Describes the radiotap parser state. Fields prefixed with an underscore
+ * must not be used by users of the parser, only by the parser internally.
*/
struct ieee80211_radiotap_iterator {
- struct ieee80211_radiotap_header *rtheader;
- int max_length;
- int this_arg_index;
- unsigned char *this_arg;
+ struct ieee80211_radiotap_header *_rtheader;
+ const struct ieee80211_radiotap_vendor_namespaces *_vns;
+ const struct ieee80211_radiotap_namespace *current_namespace;
- int arg_index;
- unsigned char *arg;
- uint32_t *next_bitmap;
- uint32_t bitmap_shifter;
+ unsigned char *_arg, *_next_ns_data;
+ uint32_t *_next_bitmap;
+
+ unsigned char *this_arg;
+#ifdef RADIOTAP_SUPPORT_OVERRIDES
+ const struct radiotap_override *overrides;
+ int n_overrides;
+#endif
+ int this_arg_index;
+ int this_arg_size;
+
+ int is_radiotap_ns;
+
+ int _max_length;
+ int _arg_index;
+ uint32_t _bitmap_shifter;
+ int _reset_on_ext;
};
extern int ieee80211_radiotap_iterator_init(
- struct ieee80211_radiotap_iterator *iterator,
- struct ieee80211_radiotap_header *radiotap_header,
- int max_length);
+ struct ieee80211_radiotap_iterator *iterator,
+ struct ieee80211_radiotap_header *radiotap_header,
+ int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns);
extern int ieee80211_radiotap_iterator_next(
- struct ieee80211_radiotap_iterator *iterator);
+ struct ieee80211_radiotap_iterator *iterator);
#endif /* __RADIOTAP_ITER_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 01be089..abffaae 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -1861,10 +1861,10 @@
* skipped when processing scan results.
*/
ret = wpa_blacklist_add(wpa_s, bssid);
- if (ret != 0)
+ if (ret < 0)
return -1;
ret = wpa_blacklist_add(wpa_s, bssid);
- if (ret != 0)
+ if (ret < 0)
return -1;
os_memcpy(buf, "OK\n", 3);
return 3;
@@ -5819,7 +5819,7 @@
continue;
ework = work->ctx;
wpa_dbg(wpa_s, MSG_DEBUG,
- "Flushing %sexternal radio work %u (%s)",
+ "Flushing%s external radio work %u (%s)",
work->started ? " started" : "", ework->id,
ework->type);
if (work->started)
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 7aee923..1aec9be 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -83,7 +83,7 @@
#define WPAS_DBUS_NEW_IFACE_P2P_GROUPMEMBER \
WPAS_DBUS_NEW_INTERFACE ".GroupMember"
-/* Errors */
+/* Top-level Errors */
#define WPAS_DBUS_ERROR_UNKNOWN_ERROR \
WPAS_DBUS_NEW_INTERFACE ".UnknownError"
#define WPAS_DBUS_ERROR_INVALID_ARGS \
@@ -120,6 +120,9 @@
#define WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM \
WPAS_DBUS_NEW_INTERFACE ".SubscriptionNotYou"
+/* Interface-level errors */
+#define WPAS_DBUS_ERROR_IFACE_SCAN_ERROR \
+ WPAS_DBUS_NEW_IFACE_INTERFACE ".ScanError"
void wpas_dbus_subscribe_noc(struct wpas_dbus_priv *priv);
void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index ffa59b2..33a1ba9 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -116,6 +116,27 @@
}
+/**
+ * wpas_dbus_error_scan_error - Return a new ScanError error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * @error: Optional string to be used as the error message
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return a scan error
+ */
+DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message,
+ const char *error)
+{
+ DBusMessage *reply;
+
+ reply = dbus_message_new_error(message,
+ WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
+ error);
+
+ return reply;
+}
+
+
static const char *dont_quote[] = {
"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
@@ -1330,7 +1351,10 @@
"passive scan");
goto out;
} else if (params.freqs && params.freqs[0]) {
- wpa_supplicant_trigger_scan(wpa_s, ¶ms);
+ if (wpa_supplicant_trigger_scan(wpa_s, ¶ms)) {
+ reply = wpas_dbus_error_scan_error(
+ message, "Scan request rejected");
+ }
} else {
wpa_s->scan_req = MANUAL_SCAN_REQ;
wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -1343,7 +1367,10 @@
#ifdef CONFIG_AUTOSCAN
autoscan_deinit(wpa_s);
#endif /* CONFIG_AUTOSCAN */
- wpa_supplicant_trigger_scan(wpa_s, ¶ms);
+ if (wpa_supplicant_trigger_scan(wpa_s, ¶ms)) {
+ reply = wpas_dbus_error_scan_error(
+ message, "Scan request rejected");
+ }
} else {
wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
"Unknown scan type: %s", type);
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index fc00b68..7eedd83 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2724,10 +2724,52 @@
}
-static void wpa_supplicant_update_channel_list(struct wpa_supplicant *wpa_s)
+static const char * reg_init_str(enum reg_change_initiator init)
+{
+ switch (init) {
+ case REGDOM_SET_BY_CORE:
+ return "CORE";
+ case REGDOM_SET_BY_USER:
+ return "USER";
+ case REGDOM_SET_BY_DRIVER:
+ return "DRIVER";
+ case REGDOM_SET_BY_COUNTRY_IE:
+ return "COUNTRY_IE";
+ case REGDOM_BEACON_HINT:
+ return "BEACON_HINT";
+ }
+ return "?";
+}
+
+
+static const char * reg_type_str(enum reg_type type)
+{
+ switch (type) {
+ case REGDOM_TYPE_UNKNOWN:
+ return "UNKNOWN";
+ case REGDOM_TYPE_COUNTRY:
+ return "COUNTRY";
+ case REGDOM_TYPE_WORLD:
+ return "WORLD";
+ case REGDOM_TYPE_CUSTOM_WORLD:
+ return "CUSTOM_WORLD";
+ case REGDOM_TYPE_INTERSECTION:
+ return "INTERSECTION";
+ }
+ return "?";
+}
+
+
+static void wpa_supplicant_update_channel_list(
+ struct wpa_supplicant *wpa_s, struct channel_list_changed *info)
{
struct wpa_supplicant *ifs;
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REGDOM_CHANGE "init=%s type=%s%s%s",
+ reg_init_str(info->type), reg_type_str(info->type),
+ info->alpha2[0] ? " alpha2=" : "",
+ info->alpha2[0] ? info->alpha2 : "");
+
if (wpa_s->drv_priv == NULL)
return; /* Ignore event during drv initialization */
@@ -3272,6 +3314,12 @@
data->eapol_rx.data_len);
break;
case EVENT_SIGNAL_CHANGE:
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SIGNAL_CHANGE
+ "above=%d signal=%d noise=%d txrate=%d",
+ data->signal_change.above_threshold,
+ data->signal_change.current_signal,
+ data->signal_change.current_noise,
+ data->signal_change.current_txrate);
bgscan_notify_signal_change(
wpa_s, data->signal_change.above_threshold,
data->signal_change.current_signal,
@@ -3324,7 +3372,8 @@
wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
break;
case EVENT_CHANNEL_LIST_CHANGED:
- wpa_supplicant_update_channel_list(wpa_s);
+ wpa_supplicant_update_channel_list(
+ wpa_s, &data->channel_list_changed);
break;
case EVENT_INTERFACE_UNAVAILABLE:
#ifdef CONFIG_P2P
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 5c6f625..a9fbf00 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -4382,7 +4382,7 @@
}
if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
- !ssid->ext_psk)
+ (!ssid->passphrase || ssid->ssid_len != 0) && !ssid->ext_psk)
return 1;
return 0;
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 3358250..629d886 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -962,6 +962,9 @@
# 0 = Enable MAX-AMSDU if hardware supports it.
# 1 = Disable AMSDU
#
+# ampdu_factor: Maximum A-MPDU Length Exponent
+# Value: 0-3, see 7.3.2.56.3 in IEEE Std 802.11n-2009.
+#
# ampdu_density: Allow overriding AMPDU density configuration.
# Treated as hint by the kernel.
# -1 = Do not make any changes.
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 22b8e71..2b58749 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -52,6 +52,25 @@
}
+static void wpas_wps_assoc_with_cred(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ int use_fast_assoc = timeout_ctx != NULL;
+
+ wpa_printf(MSG_DEBUG, "WPS: Continuing association after eapol_cb");
+ if (!use_fast_assoc ||
+ wpa_supplicant_fast_associate(wpa_s) != 1)
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
+
+
+static void wpas_wps_assoc_with_cred_cancel(struct wpa_supplicant *wpa_s)
+{
+ eloop_cancel_timeout(wpas_wps_assoc_with_cred, wpa_s, (void *) 0);
+ eloop_cancel_timeout(wpas_wps_assoc_with_cred, wpa_s, (void *) 1);
+}
+
+
int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
{
#ifdef CONFIG_P2P
@@ -124,9 +143,18 @@
wpabuf_free(wps);
}
- if (!use_fast_assoc ||
- wpa_supplicant_fast_associate(wpa_s) != 1)
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+ /*
+ * Complete the next step from an eloop timeout to allow pending
+ * driver events related to the disconnection to be processed
+ * first. This makes it less likely for disconnection event to
+ * cause problems with the following connection.
+ */
+ wpa_printf(MSG_DEBUG, "WPS: Continue association from timeout");
+ wpas_wps_assoc_with_cred_cancel(wpa_s);
+ eloop_register_timeout(0, 10000,
+ wpas_wps_assoc_with_cred, wpa_s,
+ use_fast_assoc ? (void *) 1 :
+ (void *) 0);
return 1;
}
@@ -370,6 +398,17 @@
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL)
return -1;
+ if (wpa_s->current_ssid) {
+ /*
+ * Should the GO issue multiple credentials for some
+ * reason, each credential should be marked as a
+ * temporary P2P group similarly to the one that gets
+ * marked as such based on the pre-configured values
+ * used for the WPS network block.
+ */
+ ssid->p2p_group = wpa_s->current_ssid->p2p_group;
+ ssid->temporary = wpa_s->current_ssid->temporary;
+ }
wpas_notify_network_added(wpa_s, ssid);
}
@@ -1420,6 +1459,7 @@
void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
{
+ wpas_wps_assoc_with_cred_cancel(wpa_s);
eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL);