Accumulative patch from commit 20a0b03debef66cc57b0c34a05f8be5229be907c
atheros: Fix auth_alg configuration for static WEP
nl80211: Implement set_rate_sets for non-hostapd AP case
nl80211: Enable more AP callbacks for non-hostapd AP mode
nl80211: Re-order functions to group AP/hostapd specific code
Remove compiler warning for non-P2P builds
random: Add support for maintaining internal entropy store over restarts
Fix a compiler warning on WPS-AP-without-UPnP builds
P2P: Retry provision discovery requests in IDLE state
P2P: Add callback for provision discovery failure
P2P: Add wpas_notify_p2p_provision_discovery()
P2P: Add group started notification
DBus: Move wpas_dbus_new_decompose_object_path()
DBus: Refactor array adding, add binary arrays
DBus: Add support for P2P primitives
DBus: Fix some typos on comments
Fix CONFIG_AP=y build without CONFIG_P2P=y
Fix non-P2P D-Bus build
nl80211: Add support for driver-based PMKSA cache
P2P: Start GO without extra scan step
Remove a compiler warning on uninitialized variable
Add EVENT_RX_ACTION handler for hostapd
Fix hostapd build without NEED_AP_MLME=y
Fix AP selection to check privacy mismatch and IBSS with WPA/RSN IE
bsd: Fix set_key() sequence number endian issue
Add a copyright and license statement for a radiotap header file
Use nl80211 as an example instead of WEXT
Add notes for CONFIG_WPS_ER build configuration option
Fix CONFIG_NO_WPA_PASSPHRASE=y build
hostapd: Don't mask out non-symmetric STA HT caps
P2P: Enable P2P capability advertisement on D-Bus
P2P: Update D-Bus network object semantics during group formation
P2P: Show P2P peer signal level in D-Bus P2P device properties
P2P: Fix P2P device signal level type in D-Bus
P2P: Add dissasoc_low_ack in P2P device properties
P2P: More complete persistent group management over D-Bus
P2P: Add WpsFailed signal in P2P D-Bus
P2P: Update listen and operating channel from P2P D-Bus
P2P: Fix WpsFailed signal in P2P D-Bus
atheros: Fix glibc 'invalid pointer' error when WPA_TRACE is enabled
Clear WPA and EAPOL state machine config pointer on network removal
20a0b03debef66cc57b0c34a05f8be5229be907c
Change-Id: I2b83bf86ba9c7a9a218638be7b4de31d209cdde1
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 36bb826..f6076af 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -194,4 +194,12 @@
return hapd->driver->set_radius_acl_expire(hapd->drv_priv, mac);
}
+static inline int hostapd_drv_set_authmode(struct hostapd_data *hapd,
+ int auth_algs)
+{
+ if (hapd->driver == NULL || hapd->driver->set_authmode == NULL)
+ return 0;
+ return hapd->driver->set_authmode(hapd->drv_priv, auth_algs);
+}
+
#endif /* AP_DRV_OPS */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 02b7ecf..fc4bc31 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -396,6 +396,46 @@
}
+static void hostapd_rx_action(struct hostapd_data *hapd,
+ struct rx_action *rx_action)
+{
+ struct rx_mgmt rx_mgmt;
+ u8 *buf;
+ struct ieee80211_hdr *hdr;
+
+ wpa_printf(MSG_DEBUG, "EVENT_RX_ACTION DA=" MACSTR " SA=" MACSTR
+ " BSSID=" MACSTR " category=%u",
+ MAC2STR(rx_action->da), MAC2STR(rx_action->sa),
+ MAC2STR(rx_action->bssid), rx_action->category);
+ wpa_hexdump(MSG_MSGDUMP, "Received action frame contents",
+ rx_action->data, rx_action->len);
+
+ buf = os_zalloc(24 + 1 + rx_action->len);
+ if (buf == NULL)
+ return;
+ hdr = (struct ieee80211_hdr *) buf;
+ hdr->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ACTION);
+ if (rx_action->category == WLAN_ACTION_SA_QUERY) {
+ /*
+ * Assume frame was protected; it would have been dropped if
+ * not.
+ */
+ hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
+ }
+ os_memcpy(hdr->addr1, rx_action->da, ETH_ALEN);
+ os_memcpy(hdr->addr2, rx_action->sa, ETH_ALEN);
+ os_memcpy(hdr->addr3, rx_action->bssid, ETH_ALEN);
+ buf[24] = rx_action->category;
+ os_memcpy(buf + 24 + 1, rx_action->data, rx_action->len);
+ os_memset(&rx_mgmt, 0, sizeof(rx_mgmt));
+ rx_mgmt.frame = buf;
+ rx_mgmt.frame_len = 24 + 1 + rx_action->len;
+ hostapd_mgmt_rx(hapd, &rx_mgmt);
+ os_free(buf);
+}
+
+
static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
size_t len, u16 stype, int ok)
{
@@ -530,6 +570,14 @@
break;
hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
break;
+#ifdef NEED_AP_MLME
+ case EVENT_RX_ACTION:
+ if (data->rx_action.da == NULL || data->rx_action.sa == NULL ||
+ data->rx_action.bssid == NULL)
+ break;
+ hostapd_rx_action(hapd, &data->rx_action);
+ break;
+#endif /* NEED_AP_MLME */
default:
wpa_printf(MSG_DEBUG, "Unknown event %d", event);
break;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 32db668..d8af571 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -306,6 +306,12 @@
return 0;
}
+ /*
+ * When IEEE 802.1X is not enabled, the driver may need to know how to
+ * set authentication algorithms for static WEP.
+ */
+ hostapd_drv_set_authmode(hapd, hapd->conf->auth_algs);
+
for (i = 0; i < 4; i++) {
if (hapd->conf->ssid.wep.key[i] &&
hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i,
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 3dce5cb..6c3696f 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -250,8 +250,14 @@
return;
os_memcpy(neg_ht_cap, ht_cap, sizeof(*neg_ht_cap));
cap = le_to_host16(neg_ht_cap->ht_capabilities_info);
- cap &= hapd->iconf->ht_capab;
- cap |= (hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_DISABLED);
+
+ /*
+ * Mask out HT features we don't support, but don't overwrite
+ * non-symmetric features like STBC and SMPS. Just because
+ * we're not in dynamic SMPS mode the STA might still be.
+ */
+ cap &= (hapd->iconf->ht_capab | HT_CAP_INFO_RX_STBC_MASK |
+ HT_CAP_INFO_TX_STBC | HT_CAP_INFO_SMPS_MASK);
/*
* STBC needs to be handled specially
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 217f9f9..6b6fd4b 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -1852,6 +1852,7 @@
const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
{
+ *len = 0;
if (sm == NULL)
return NULL;
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index fc927f9..640e8cd 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -890,7 +890,7 @@
{
struct wps_context *wps = hapd->wps;
- if (hapd->wps == NULL)
+ if (wps == NULL)
return 0;
#ifdef CONFIG_WPS_UPNP
diff --git a/src/crypto/random.c b/src/crypto/random.c
index a30afde..f545917 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -57,12 +57,18 @@
static int random_fd = -1;
#endif /* __linux__ */
static unsigned int own_pool_ready = 0;
+#define RANDOM_ENTROPY_SIZE 20
+static char *random_entropy_file = NULL;
+static int random_entropy_file_read = 0;
#define MIN_COLLECT_ENTROPY 1000
static unsigned int entropy = 0;
static unsigned int total_collected = 0;
+static void random_write_entropy(void);
+
+
static u32 __ROL32(u32 x, u32 y)
{
return (x << (y & 31)) | (x >> (32 - (y & 31)));
@@ -232,8 +238,12 @@
dummy_key_avail += res;
close(fd);
- if (dummy_key_avail == sizeof(dummy_key))
+ if (dummy_key_avail == sizeof(dummy_key)) {
+ if (own_pool_ready < MIN_READY_MARK)
+ own_pool_ready = MIN_READY_MARK;
+ random_write_entropy();
return 1;
+ }
wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong "
"random data available from /dev/random",
@@ -261,6 +271,7 @@
own_pool_ready++;
wpa_printf(MSG_DEBUG, "random: Mark internal entropy pool to be "
"ready (count=%u/%u)", own_pool_ready, MIN_READY_MARK);
+ random_write_entropy();
}
@@ -298,15 +309,84 @@
(unsigned) (sizeof(dummy_key) - dummy_key_avail));
dummy_key_avail += res;
- if (dummy_key_avail == sizeof(dummy_key))
+ if (dummy_key_avail == sizeof(dummy_key)) {
random_close_fd();
+ if (own_pool_ready < MIN_READY_MARK)
+ own_pool_ready = MIN_READY_MARK;
+ random_write_entropy();
+ }
}
#endif /* __linux__ */
-void random_init(void)
+static void random_read_entropy(void)
{
+ char *buf;
+ size_t len;
+
+ if (!random_entropy_file)
+ return;
+
+ buf = os_readfile(random_entropy_file, &len);
+ if (buf == NULL)
+ return; /* entropy file not yet available */
+
+ if (len != 1 + RANDOM_ENTROPY_SIZE) {
+ wpa_printf(MSG_DEBUG, "random: Invalid entropy file %s",
+ random_entropy_file);
+ os_free(buf);
+ return;
+ }
+
+ own_pool_ready = (u8) buf[0];
+ random_add_randomness(buf + 1, RANDOM_ENTROPY_SIZE);
+ random_entropy_file_read = 1;
+ os_free(buf);
+ wpa_printf(MSG_DEBUG, "random: Added entropy from %s "
+ "(own_pool_ready=%u)",
+ random_entropy_file, own_pool_ready);
+}
+
+
+static void random_write_entropy(void)
+{
+ char buf[RANDOM_ENTROPY_SIZE];
+ FILE *f;
+ u8 opr;
+
+ if (!random_entropy_file)
+ return;
+
+ random_get_bytes(buf, RANDOM_ENTROPY_SIZE);
+
+ f = fopen(random_entropy_file, "wb");
+ if (f == NULL) {
+ wpa_printf(MSG_ERROR, "random: Could not write %s",
+ random_entropy_file);
+ return;
+ }
+
+ opr = own_pool_ready > 0xff ? 0xff : own_pool_ready;
+ fwrite(&opr, 1, 1, f);
+ fwrite(buf, RANDOM_ENTROPY_SIZE, 1, f);
+ fclose(f);
+
+ wpa_printf(MSG_DEBUG, "random: Updated entropy file %s "
+ "(own_pool_ready=%u)",
+ random_entropy_file, own_pool_ready);
+}
+
+
+void random_init(const char *entropy_file)
+{
+ os_free(random_entropy_file);
+ if (entropy_file)
+ random_entropy_file = os_strdup(entropy_file);
+ else
+ random_entropy_file = NULL;
+ random_read_entropy();
+
#ifdef __linux__
if (random_fd >= 0)
return;
@@ -326,6 +406,8 @@
eloop_register_read_sock(random_fd, random_read_fd, NULL, NULL);
#endif /* __linux__ */
+
+ random_write_entropy();
}
@@ -334,4 +416,7 @@
#ifdef __linux__
random_close_fd();
#endif /* __linux__ */
+ random_write_entropy();
+ os_free(random_entropy_file);
+ random_entropy_file = NULL;
}
diff --git a/src/crypto/random.h b/src/crypto/random.h
index 5dabd2b..1048bb4 100644
--- a/src/crypto/random.h
+++ b/src/crypto/random.h
@@ -16,14 +16,14 @@
#define RANDOM_H
#ifdef CONFIG_NO_RANDOM_POOL
-#define random_init() do { } while (0)
+#define random_init(e) do { } while (0)
#define random_deinit() do { } while (0)
#define random_add_randomness(b, l) do { } while (0)
#define random_get_bytes(b, l) os_get_random((b), (l))
#define random_pool_ready() 1
#define random_mark_pool_ready() do { } while (0)
#else /* CONFIG_NO_RANDOM_POOL */
-void random_init(void);
+void random_init(const char *entropy_file);
void random_deinit(void);
void random_add_randomness(const void *buf, size_t len);
int random_get_bytes(void *buf, size_t len);
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 2a3efa4..c7dbdc1 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2243,6 +2243,18 @@
int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info);
/**
+ * set_authmode - Set authentication algorithm(s) for static WEP
+ * @priv: Private driver interface data
+ * @authmode: 1=Open System, 2=Shared Key, 3=both
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to set authentication algorithms for AP
+ * mode when static WEP is used. If the driver uses user space MLME/SME
+ * implementation, there is no need to implement this function.
+ */
+ int (*set_authmode)(void *priv, int authmode);
+
+ /**
* driver_cmd - execute driver-specific command
* @priv: private driver interface data
* @cmd: command to execute
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 6ac1cea..1e78f6e 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -1116,7 +1116,7 @@
drv->we_version = range->we_version_compiled;
}
- free(range);
+ os_free(range);
return 0;
}
@@ -1357,6 +1357,23 @@
return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);
}
+static int atheros_set_authmode(void *priv, int auth_algs)
+{
+ int authmode;
+
+ if ((auth_algs & WPA_AUTH_ALG_OPEN) &&
+ (auth_algs & WPA_AUTH_ALG_SHARED))
+ authmode = IEEE80211_AUTH_AUTO;
+ else if (auth_algs & WPA_AUTH_ALG_OPEN)
+ authmode = IEEE80211_AUTH_OPEN;
+ else if (auth_algs & WPA_AUTH_ALG_SHARED)
+ authmode = IEEE80211_AUTH_SHARED;
+ else
+ return -1;
+
+ return set80211param(priv, IEEE80211_PARAM_AUTHMODE, authmode);
+}
+
const struct wpa_driver_ops wpa_driver_atheros_ops = {
.name = "atheros",
.hapd_init = atheros_init,
@@ -1378,4 +1395,5 @@
.sta_clear_stats = atheros_sta_clear_stats,
.commit = atheros_commit,
.set_ap_wps_ie = atheros_set_ap_wps_ie,
+ .set_authmode = atheros_set_authmode,
};
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 1b52865..4596a51 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -345,8 +345,20 @@
if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
wk.ik_flags |= IEEE80211_KEY_DEFAULT;
wk.ik_keylen = key_len;
- if (seq)
+ if (seq) {
+#ifdef WORDS_BIGENDIAN
+ /*
+ * wk.ik_keyrsc is in host byte order (big endian), need to
+ * swap it to match with the byte order used in WPA.
+ */
+ int i;
+ u8 *keyrsc = (u8 *) &wk.ik_keyrsc;
+ for (i = 0; i < seq_len; i++)
+ keyrsc[WPA_KEY_RSC_LEN - i - 1] = seq[i];
+#else /* WORDS_BIGENDIAN */
os_memcpy(&wk.ik_keyrsc, seq, seq_len);
+#endif /* WORDS_BIGENDIAN */
+ }
os_memcpy(wk.ik_keydata, key, key_len);
return set80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index b4f01fa..cfc9372 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -5043,70 +5043,17 @@
}
-#ifdef HOSTAPD
-
-static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+/* Set kernel driver on given frequency (MHz) */
+static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
{
- int i;
- int *old;
-
- wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d",
- ifidx);
- for (i = 0; i < drv->num_if_indices; i++) {
- if (drv->if_indices[i] == 0) {
- drv->if_indices[i] = ifidx;
- return;
- }
- }
-
- if (drv->if_indices != drv->default_if_indices)
- old = drv->if_indices;
- else
- old = NULL;
-
- drv->if_indices = os_realloc(old,
- sizeof(int) * (drv->num_if_indices + 1));
- if (!drv->if_indices) {
- if (!old)
- drv->if_indices = drv->default_if_indices;
- else
- drv->if_indices = old;
- wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
- "interfaces");
- wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
- return;
- } else if (!old)
- os_memcpy(drv->if_indices, drv->default_if_indices,
- sizeof(drv->default_if_indices));
- drv->if_indices[drv->num_if_indices] = ifidx;
- drv->num_if_indices++;
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ return wpa_driver_nl80211_set_freq(drv, freq->freq, freq->ht_enabled,
+ freq->sec_channel_offset);
}
-static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
- int i;
-
- for (i = 0; i < drv->num_if_indices; i++) {
- if (drv->if_indices[i] == ifidx) {
- drv->if_indices[i] = 0;
- break;
- }
- }
-}
-
-
-static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
-{
- int i;
-
- for (i = 0; i < drv->num_if_indices; i++)
- if (drv->if_indices[i] == ifidx)
- return 1;
-
- return 0;
-}
-
+#if defined(HOSTAPD) || defined(CONFIG_AP)
static inline int min_int(int a, int b)
{
@@ -5193,20 +5140,6 @@
return -ENOBUFS;
}
-#endif /* HOSTAPD */
-
-
-/* Set kernel driver on given frequency (MHz) */
-static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
-{
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- return wpa_driver_nl80211_set_freq(drv, freq->freq, freq->ht_enabled,
- freq->sec_channel_offset);
-}
-
-
-#ifdef HOSTAPD
static int i802_set_rts(void *priv, int rts)
{
@@ -5511,37 +5444,6 @@
}
-static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
- const char *bridge_ifname)
-{
- struct i802_bss *bss = priv;
- struct wpa_driver_nl80211_data *drv = bss->drv;
- char name[IFNAMSIZ + 1];
-
- os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
- wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
- " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
- if (val) {
- if (!if_nametoindex(name)) {
- if (nl80211_create_iface(drv, name,
- NL80211_IFTYPE_AP_VLAN,
- NULL, 1) < 0)
- return -1;
- if (bridge_ifname &&
- linux_br_add_if(drv->ioctl_sock, bridge_ifname,
- name) < 0)
- return -1;
- }
- linux_set_iface_flags(drv->ioctl_sock, name, 1);
- return i802_set_sta_vlan(priv, addr, name, 0);
- } else {
- i802_set_sta_vlan(priv, addr, bss->ifname, 0);
- return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
- name);
- }
-}
-
-
static int i802_set_ht_params(void *priv, const u8 *ht_capab,
size_t ht_capab_len, const u8 *ht_oper,
size_t ht_oper_len)
@@ -5555,26 +5457,6 @@
}
-static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
-{
- struct wpa_driver_nl80211_data *drv = eloop_ctx;
- struct sockaddr_ll lladdr;
- unsigned char buf[3000];
- int len;
- socklen_t fromlen = sizeof(lladdr);
-
- len = recvfrom(sock, buf, sizeof(buf), 0,
- (struct sockaddr *)&lladdr, &fromlen);
- if (len < 0) {
- perror("recv");
- return;
- }
-
- if (have_ifidx(drv, lladdr.sll_ifindex))
- drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
-}
-
-
static int i802_get_inact_sec(void *priv, const u8 *addr)
{
struct hostap_sta_driver_data data;
@@ -5596,9 +5478,6 @@
return 0;
}
-#endif /* HOSTAPD */
-
-#if defined(HOSTAPD) || defined(CONFIG_AP)
static int i802_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
int reason)
@@ -5641,6 +5520,120 @@
#ifdef HOSTAPD
+static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+ int i;
+ int *old;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Add own interface ifindex %d",
+ ifidx);
+ for (i = 0; i < drv->num_if_indices; i++) {
+ if (drv->if_indices[i] == 0) {
+ drv->if_indices[i] = ifidx;
+ return;
+ }
+ }
+
+ if (drv->if_indices != drv->default_if_indices)
+ old = drv->if_indices;
+ else
+ old = NULL;
+
+ drv->if_indices = os_realloc(old,
+ sizeof(int) * (drv->num_if_indices + 1));
+ if (!drv->if_indices) {
+ if (!old)
+ drv->if_indices = drv->default_if_indices;
+ else
+ drv->if_indices = old;
+ wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
+ "interfaces");
+ wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
+ return;
+ } else if (!old)
+ os_memcpy(drv->if_indices, drv->default_if_indices,
+ sizeof(drv->default_if_indices));
+ drv->if_indices[drv->num_if_indices] = ifidx;
+ drv->num_if_indices++;
+}
+
+
+static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+ int i;
+
+ for (i = 0; i < drv->num_if_indices; i++) {
+ if (drv->if_indices[i] == ifidx) {
+ drv->if_indices[i] = 0;
+ break;
+ }
+ }
+}
+
+
+static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+ int i;
+
+ for (i = 0; i < drv->num_if_indices; i++)
+ if (drv->if_indices[i] == ifidx)
+ return 1;
+
+ return 0;
+}
+
+
+static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val,
+ const char *bridge_ifname)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ char name[IFNAMSIZ + 1];
+
+ os_snprintf(name, sizeof(name), "%s.sta%d", bss->ifname, aid);
+ wpa_printf(MSG_DEBUG, "nl80211: Set WDS STA addr=" MACSTR
+ " aid=%d val=%d name=%s", MAC2STR(addr), aid, val, name);
+ if (val) {
+ if (!if_nametoindex(name)) {
+ if (nl80211_create_iface(drv, name,
+ NL80211_IFTYPE_AP_VLAN,
+ NULL, 1) < 0)
+ return -1;
+ if (bridge_ifname &&
+ linux_br_add_if(drv->ioctl_sock, bridge_ifname,
+ name) < 0)
+ return -1;
+ }
+ linux_set_iface_flags(drv->ioctl_sock, name, 1);
+ return i802_set_sta_vlan(priv, addr, name, 0);
+ } else {
+ i802_set_sta_vlan(priv, addr, bss->ifname, 0);
+ return wpa_driver_nl80211_if_remove(priv, WPA_IF_AP_VLAN,
+ name);
+ }
+}
+
+
+static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct wpa_driver_nl80211_data *drv = eloop_ctx;
+ struct sockaddr_ll lladdr;
+ unsigned char buf[3000];
+ int len;
+ socklen_t fromlen = sizeof(lladdr);
+
+ len = recvfrom(sock, buf, sizeof(buf), 0,
+ (struct sockaddr *)&lladdr, &fromlen);
+ if (len < 0) {
+ perror("recv");
+ return;
+ }
+
+ if (have_ifidx(drv, lladdr.sll_ifindex))
+ drv_event_eapol_rx(drv->ctx, lladdr.sll_addr, buf, len);
+}
+
+
static int i802_check_bridge(struct wpa_driver_nl80211_data *drv,
struct i802_bss *bss,
const char *brname, const char *ifname)
@@ -6562,6 +6555,55 @@
}
+static int nl80211_pmkid(struct i802_bss *bss, int cmd, const u8 *bssid,
+ const u8 *pmkid)
+{
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(bss->drv->nl80211), 0, 0,
+ cmd, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
+ if (pmkid)
+ NLA_PUT(msg, NL80211_ATTR_PMKID, 16, pmkid);
+ if (bssid)
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
+
+ return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+ nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+static int nl80211_add_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
+{
+ struct i802_bss *bss = priv;
+ wpa_printf(MSG_DEBUG, "nl80211: Add PMKID for " MACSTR, MAC2STR(bssid));
+ return nl80211_pmkid(bss, NL80211_CMD_SET_PMKSA, bssid, pmkid);
+}
+
+
+static int nl80211_remove_pmkid(void *priv, const u8 *bssid, const u8 *pmkid)
+{
+ struct i802_bss *bss = priv;
+ wpa_printf(MSG_DEBUG, "nl80211: Delete PMKID for " MACSTR,
+ MAC2STR(bssid));
+ return nl80211_pmkid(bss, NL80211_CMD_DEL_PMKSA, bssid, pmkid);
+}
+
+
+static int nl80211_flush_pmkid(void *priv)
+{
+ struct i802_bss *bss = priv;
+ wpa_printf(MSG_DEBUG, "nl80211: Flush PMKIDs");
+ return nl80211_pmkid(bss, NL80211_CMD_FLUSH_PMKSA, NULL, NULL);
+}
+
+
const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.name = "nl80211",
.desc = "Linux nl80211/cfg80211",
@@ -6594,6 +6636,9 @@
#ifdef HOSTAPD
.hapd_init = i802_init,
.hapd_deinit = i802_deinit,
+ .set_wds_sta = i802_set_wds_sta,
+#endif /* HOSTAPD */
+#if defined(HOSTAPD) || defined(CONFIG_AP)
.get_seqnum = i802_get_seqnum,
.flush = i802_flush,
.read_sta_data = i802_read_sta_data,
@@ -6601,16 +6646,13 @@
.sta_clear_stats = i802_sta_clear_stats,
.set_rts = i802_set_rts,
.set_frag = i802_set_frag,
- .set_rate_sets = i802_set_rate_sets,
.set_cts_protect = i802_set_cts_protect,
.set_preamble = i802_set_preamble,
.set_short_slot_time = i802_set_short_slot_time,
.set_tx_queue_params = i802_set_tx_queue_params,
.set_sta_vlan = i802_set_sta_vlan,
- .set_wds_sta = i802_set_wds_sta,
.set_ht_params = i802_set_ht_params,
-#endif /* HOSTAPD */
-#if defined(HOSTAPD) || defined(CONFIG_AP)
+ .set_rate_sets = i802_set_rate_sets,
.sta_deauth = i802_sta_deauth,
.sta_disassoc = i802_sta_disassoc,
#endif /* HOSTAPD || CONFIG_AP */
@@ -6631,4 +6673,7 @@
.set_intra_bss = nl80211_set_intra_bss,
.set_param = nl80211_set_param,
.get_radio_name = nl80211_get_radio_name,
+ .add_pmkid = nl80211_add_pmkid,
+ .remove_pmkid = nl80211_remove_pmkid,
+ .flush_pmkid = nl80211_flush_pmkid,
};
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 653609e..191099a 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -576,7 +576,7 @@
dev->listen_freq = freq;
if (msg.group_info)
dev->oper_freq = freq;
- dev->level = level;
+ dev->info.level = level;
p2p_copy_wps_info(dev, 0, &msg);
@@ -2250,19 +2250,81 @@
p2p_set_timeout(p2p, 0, 200000);
}
+
+/**
+ * p2p_retry_pd - Retry any pending provision disc requests in IDLE state
+ * @p2p: P2P module context from p2p_init()
+ */
+void p2p_retry_pd(struct p2p_data *p2p)
+{
+ struct p2p_device *dev;
+
+ if (p2p->state != P2P_IDLE)
+ return;
+
+ /*
+ * Retry the prov disc req attempt only for the peer that the user had
+ * requested for and provided a join has not been initiated on it
+ * in the meantime.
+ */
+
+ dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+ if (os_memcmp(p2p->pending_pd_devaddr,
+ dev->info.p2p_device_addr, ETH_ALEN) != 0)
+ continue;
+ if (!dev->req_config_methods)
+ continue;
+ if (dev->flags & P2P_DEV_PD_FOR_JOIN)
+ continue;
+
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
+ "pending Provisioning Discovery Request to "
+ MACSTR " (config methods 0x%x)",
+ MAC2STR(dev->info.p2p_device_addr),
+ dev->req_config_methods);
+ p2p_send_prov_disc_req(p2p, dev, 0);
+ return;
+ }
+}
+
+
static void p2p_prov_disc_cb(struct p2p_data *p2p, int success)
{
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Provision Discovery Request TX callback: success=%d",
success);
- p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
+ /*
+ * Postpone resetting the pending action state till after we actually
+ * time out. This allows us to take some action like notifying any
+ * interested parties about no response to the request.
+ *
+ * When the timer (below) goes off we check in IDLE, SEARCH, or
+ * LISTEN_ONLY state, which are the only allowed states to issue a PD
+ * requests in, if this was still pending and then raise notification.
+ */
if (!success) {
+ p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
if (p2p->state != P2P_IDLE)
p2p_continue_find(p2p);
+ else if (p2p->user_initiated_pd) {
+ p2p->pending_action_state = P2P_PENDING_PD;
+ p2p_set_timeout(p2p, 0, 300000);
+ }
return;
}
+ /*
+ * This postponing, of resetting pending_action_state, needs to be
+ * done only for user initiated PD requests and not internal ones.
+ */
+ if (p2p->user_initiated_pd)
+ p2p->pending_action_state = P2P_PENDING_PD;
+ else
+ p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
/* Wait for response from the peer */
if (p2p->state == P2P_SEARCH)
p2p_set_state(p2p, P2P_PD_DURING_FIND);
@@ -2653,6 +2715,34 @@
}
+static void p2p_timeout_prov_disc_req(struct p2p_data *p2p)
+{
+ p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+
+ /*
+ * For user initiated PD requests that we have not gotten any responses
+ * for while in IDLE state, we retry them a couple of times before
+ * giving up.
+ */
+ if (!p2p->user_initiated_pd)
+ return;
+
+ wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+ "P2P: User initiated Provision Discovery Request timeout");
+
+ if (p2p->pd_retries) {
+ p2p->pd_retries--;
+ p2p_retry_pd(p2p);
+ } else {
+ if (p2p->cfg->prov_disc_fail)
+ p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx,
+ p2p->pending_pd_devaddr,
+ P2P_PROV_DISC_TIMEOUT);
+ p2p_reset_pending_pd(p2p);
+ }
+}
+
+
static void p2p_timeout_invite(struct p2p_data *p2p)
{
p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
@@ -2701,8 +2791,14 @@
switch (p2p->state) {
case P2P_IDLE:
+ /* Check if we timed out waiting for PD req */
+ if (p2p->pending_action_state == P2P_PENDING_PD)
+ p2p_timeout_prov_disc_req(p2p);
break;
case P2P_SEARCH:
+ /* Check if we timed out waiting for PD req */
+ if (p2p->pending_action_state == P2P_PENDING_PD)
+ p2p_timeout_prov_disc_req(p2p);
p2p_search(p2p);
break;
case P2P_CONNECT:
@@ -2714,6 +2810,10 @@
case P2P_GO_NEG:
break;
case P2P_LISTEN_ONLY:
+ /* Check if we timed out waiting for PD req */
+ if (p2p->pending_action_state == P2P_PENDING_PD)
+ p2p_timeout_prov_disc_req(p2p);
+
if (p2p->ext_listen_only) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Extended Listen Timing - Listen State "
@@ -2861,7 +2961,7 @@
"invitation_reqs=%u\n",
(int) (now.sec - dev->last_seen.sec),
dev->listen_freq,
- dev->level,
+ dev->info.level,
p2p_wps_method_text(dev->wps_method),
MAC2STR(dev->interface_addr),
MAC2STR(dev->member_in_go_dev),
@@ -3328,6 +3428,22 @@
}
+int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
+ int cfg_op_channel)
+{
+ if (p2p_channel_to_freq(p2p->cfg->country, op_reg_class, op_channel)
+ < 0)
+ return -1;
+
+ wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, "P2P: Set Operating channel: "
+ "reg_class %u channel %u", op_reg_class, op_channel);
+ p2p->cfg->op_reg_class = op_reg_class;
+ p2p->cfg->op_channel = op_channel;
+ p2p->cfg->cfg_op_channel = cfg_op_channel;
+ return 0;
+}
+
+
int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr,
u8 *iface_addr)
{
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 954f562..db816a6 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -180,6 +180,11 @@
char serial_number[33];
/**
+ * level - Signal level
+ */
+ int level;
+
+ /**
* config_methods - WPS Configuration Methods
*/
u16 config_methods;
@@ -210,6 +215,12 @@
struct wpabuf *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
};
+enum p2p_prov_disc_status {
+ P2P_PROV_DISC_SUCCESS,
+ P2P_PROV_DISC_TIMEOUT,
+ P2P_PROV_DISC_REJECTED,
+};
+
/**
* struct p2p_config - P2P configuration
*
@@ -603,6 +614,21 @@
void (*prov_disc_resp)(void *ctx, const u8 *peer, u16 config_methods);
/**
+ * prov_disc_fail - Callback on Provision Discovery failure
+ * @ctx: Callback context from cb_ctx
+ * @peer: Source address of the response
+ * @status: Cause of failure, will not be %P2P_PROV_DISC_SUCCESS
+ *
+ * This callback is used to indicate either a failure or no response
+ * to an earlier provision discovery request.
+ *
+ * This callback handler can be set to %NULL if provision discovery
+ * is not used or failures do not need to be indicated.
+ */
+ void (*prov_disc_fail)(void *ctx, const u8 *peer,
+ enum p2p_prov_disc_status status);
+
+ /**
* invitation_process - Optional callback for processing Invitations
* @ctx: Callback context from cb_ctx
* @sa: Source address of the Invitation Request
@@ -1470,4 +1496,15 @@
int p2p_add_wps_vendor_extension(struct p2p_data *p2p,
const struct wpabuf *vendor_ext);
+/**
+ * p2p_set_oper_channel - Set the P2P operating channel
+ * @p2p: P2P module context from p2p_init()
+ * @op_reg_class: Operating regulatory class to set
+ * @op_channel: operating channel to set
+ * @cfg_op_channel : Whether op_channel is hardcoded in configuration
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
+ int cfg_op_channel);
+
#endif /* P2P_H */
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 68b1194..52d9311 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -33,7 +33,6 @@
struct dl_list list;
struct os_time last_seen;
int listen_freq;
- int level;
enum p2p_wps_method wps_method;
struct p2p_peer_info info;
@@ -393,6 +392,23 @@
* wps_vendor_ext - WPS Vendor Extensions to add
*/
struct wpabuf *wps_vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
+
+ /*
+ * user_initiated_pd - Whether a PD request is user initiated or not.
+ */
+ u8 user_initiated_pd;
+
+ /*
+ * Keep track of which peer a given PD request was sent to.
+ * Used to raise a timeout alert in case there is no response.
+ */
+ u8 pending_pd_devaddr[ETH_ALEN];
+
+ /*
+ * Retry counter for provision discovery requests when issued
+ * in IDLE state.
+ */
+ int pd_retries;
};
/**
@@ -586,6 +602,7 @@
const u8 *data, size_t len);
int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
int join);
+void p2p_reset_pending_pd(struct p2p_data *p2p);
/* p2p_invitation.c */
void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index e064216..f7ff06c 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -21,6 +21,13 @@
#include "p2p.h"
+/*
+ * Number of retries to attempt for provision discovery requests during IDLE
+ * state in case the peer is not listening.
+ */
+#define MAX_PROV_DISC_REQ_RETRIES 10
+
+
static void p2p_build_wps_ie_config_methods(struct wpabuf *buf,
u16 config_methods)
{
@@ -215,6 +222,11 @@
return;
}
+ if (p2p->pending_action_state == P2P_PENDING_PD) {
+ os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
+ p2p->pending_action_state = P2P_NO_PENDING_ACTION;
+ }
+
if (dev->dialog_token != msg.dialog_token) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
"P2P: Ignore Provisioning Discovery Response with "
@@ -224,9 +236,20 @@
return;
}
+ /*
+ * If the response is from the peer to whom a user initiated request
+ * was sent earlier, we reset that state info here.
+ */
+ if (p2p->user_initiated_pd &&
+ os_memcmp(p2p->pending_pd_devaddr, sa, ETH_ALEN) == 0)
+ p2p_reset_pending_pd(p2p);
+
if (msg.wps_config_methods != dev->req_config_methods) {
wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected "
"our Provisioning Discovery Request");
+ if (p2p->cfg->prov_disc_fail)
+ p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
+ P2P_PROV_DISC_REJECTED);
p2p_parse_free(&msg);
goto out;
}
@@ -301,6 +324,8 @@
return -1;
}
+ os_memcpy(p2p->pending_pd_devaddr, dev->info.p2p_device_addr, ETH_ALEN);
+
wpabuf_free(req);
return 0;
}
@@ -343,5 +368,23 @@
return 0;
}
+ /*
+ * We use the join param as a cue to differentiate between user
+ * initiated PD request and one issued during finds (internal).
+ */
+ p2p->user_initiated_pd = !join;
+
+ /* Also set some retries to attempt in case of IDLE state */
+ if (p2p->user_initiated_pd && p2p->state == P2P_IDLE)
+ p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
+
return p2p_send_prov_disc_req(p2p, dev, join);
}
+
+
+void p2p_reset_pending_pd(struct p2p_data *p2p)
+{
+ p2p->user_initiated_pd = 0;
+ os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
+ p2p->pd_retries = 0;
+}
diff --git a/src/utils/radiotap_iter.h b/src/utils/radiotap_iter.h
index 92a798a..2e0e872 100644
--- a/src/utils/radiotap_iter.h
+++ b/src/utils/radiotap_iter.h
@@ -1,3 +1,18 @@
+/*
+ * 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