Cumulative patch from commit f2d6c17aa0f9107a0e8092238b849461447cdd21
f2d6c17 nl80211: Support network hierarchy of a master interface under bridge
f85399f Reserve QCA vendor specific nl80211 commands 116..118
3bd5886 hostapd: Handle running out of DFS channels
cc1af6f FST: Fix session setup failure with peer without MB IE
dfe0745 P2P: Add optional op_class argument to P2P_SET listen_channel
e4a1469 P2P: Adjust service discovery maximum fragment size for 60 GHz
c7fb678 D-Bus: Add association response status code property for failure cases
2940bf6 hostapd: Use ifname of the current context in debug messages
6448e06 hostapd: Allow use of driver-generated interface addresses
f2accfe AP: Save EAPOL received before Association Response ACK
1307301 wpaspy: Add support for TERMINATE command
a2c88a8 wpaspy: Add support for UDP connection
3e67171 hostapd: Add global TERMINATE command
618f5d0 hostapd: Add INTERFACES ctrl_iface command
180e5b9 hostapd: Update ctrl_interface for UDP to include the selected port
56e2fc2 wpa_supplicant: Add ctrl parameter to INTERFACES command
b9066c6 hostapd: Allow UDP ctrl_iface configuration to set the UDP port
56885ee hostapd: Add UDP support for ctrl_iface
acf57fa ctrl_iface_common: Use sockaddr_storage instead of sockaddr_un
89b781b hostapd: Use common functions for ctrl_iface
1a2124c wpa_supplicant: Use common functions for ctrl_iface
ca974ae Add common ctrl_iface files
d60886c wpa_supplicant: Add monitor support for global UDP ctrl_iface
f0e5d3b wpa_supplicant: Share attach/detach/send UDP ctrl_iface functions
db7fb43 wpa_supplicant: Allow UDP ctrl_iface configuration to set the UDP port
3598695 P2P: Update peer WFD IE from PD Response and GO Negotiation Response
c69ef1d P2P: Respect p2p_ignore_shared_freq on p2p_group_add
4115b05 P2P: Fix shared freq print in wpas_p2p_init_go_params()
Change-Id: Id939064b95210ee1a195f7a9f7c069da520d77ca
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index f19cac6..2d07c67 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -665,6 +665,9 @@
u8 vht_oper_centr_freq_seg0_idx;
u8 vht_oper_centr_freq_seg1_idx;
+ /* Use driver-generated interface addresses when adding multiple BSSs */
+ u8 use_driver_iface_addr;
+
#ifdef CONFIG_FST
struct fst_iface_cfg fst_cfg;
#endif /* CONFIG_FST */
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index bda23f0..47adba7 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -704,7 +704,8 @@
skip_radar);
if (!channel) {
wpa_printf(MSG_ERROR, "could not get valid channel");
- return -1;
+ hostapd_set_state(iface, HAPD_IFACE_DFS);
+ return 0;
}
iface->freq = channel->freq;
@@ -793,7 +794,6 @@
if (!channel) {
wpa_printf(MSG_ERROR, "No valid channel available");
- hostapd_setup_interface_complete(iface, err);
return err;
}
@@ -858,8 +858,9 @@
&vht_oper_centr_freq_seg1_idx,
skip_radar);
if (!channel) {
- /* FIXME: Wait for channel(s) to become available */
- hostapd_disable_iface(iface);
+ wpa_printf(MSG_INFO,
+ "%s: no DFS channels left, waiting for NOP to finish",
+ __func__);
return err;
}
@@ -982,6 +983,11 @@
/* TODO add correct implementation here */
set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
+
+ /* Handle cases where all channels were initially unavailable */
+ if (iface->state == HAPD_IFACE_DFS && !iface->cac_started)
+ hostapd_handle_dfs(iface);
+
return 0;
}
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 303786b..55ca9e8 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -512,6 +512,9 @@
if (hostapd_drv_none(hapd))
return 0;
+ if (iface->conf->use_driver_iface_addr)
+ return 0;
+
/* Generate BSSID mask that is large enough to cover the BSSIDs. */
/* Determine the bits necessary to cover the number of BSSIDs. */
@@ -905,12 +908,9 @@
hapd->started = 1;
if (!first || first == -1) {
- if (is_zero_ether_addr(conf->bssid)) {
- /* Allocate the next available BSSID. */
- do {
- inc_byte_array(hapd->own_addr, ETH_ALEN);
- } while (mac_in_conf(hapd->iconf, hapd->own_addr));
- } else {
+ u8 *addr = hapd->own_addr;
+
+ if (!is_zero_ether_addr(conf->bssid)) {
/* Allocate the configured BSSID. */
os_memcpy(hapd->own_addr, conf->bssid, ETH_ALEN);
@@ -922,11 +922,18 @@
"the radio", conf->iface);
return -1;
}
+ } else if (hapd->iconf->use_driver_iface_addr) {
+ addr = NULL;
+ } else {
+ /* Allocate the next available BSSID. */
+ do {
+ inc_byte_array(hapd->own_addr, ETH_ALEN);
+ } while (mac_in_conf(hapd->iconf, hapd->own_addr));
}
hapd->interface_added = 1;
if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
- conf->iface, hapd->own_addr, hapd,
+ conf->iface, addr, hapd,
&hapd->drv_priv, force_ifname, if_addr,
conf->bridge[0] ? conf->bridge : NULL,
first == -1)) {
@@ -935,6 +942,9 @@
hapd->interface_added = 0;
return -1;
}
+
+ if (!addr)
+ os_memcpy(hapd->own_addr, if_addr, ETH_ALEN);
}
if (conf->wmm_enabled < 0)
@@ -1859,6 +1869,7 @@
hapd->iface = hapd_iface;
hapd->driver = hapd->iconf->driver;
hapd->ctrl_sock = -1;
+ dl_list_init(&hapd->ctrl_dst);
return hapd;
}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index d6d96db..60516ae 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -41,7 +41,7 @@
size_t count;
int global_ctrl_sock;
- struct wpa_ctrl_dst *global_ctrl_dst;
+ struct dl_list global_ctrl_dst;
char *global_iface_path;
char *global_iface_name;
#ifndef CONFIG_NATIVE_WINDOWS
@@ -155,7 +155,7 @@
int tkip_countermeasures;
int ctrl_sock;
- struct wpa_ctrl_dst *ctrl_dst;
+ struct dl_list ctrl_dst;
void *ssl_ctx;
void *eap_sim_db_priv;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index b36e68d..134ae06 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -2782,6 +2782,25 @@
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
+
+ if (sta->pending_eapol_rx) {
+ struct os_reltime now, age;
+
+ os_get_reltime(&now);
+ os_reltime_sub(&now, &sta->pending_eapol_rx->rx_time, &age);
+ if (age.sec == 0 && age.usec < 200000) {
+ wpa_printf(MSG_DEBUG,
+ "Process pending EAPOL frame that was received from " MACSTR " just before association notification",
+ MAC2STR(sta->addr));
+ ieee802_1x_receive(
+ hapd, mgmt->da,
+ wpabuf_head(sta->pending_eapol_rx->buf),
+ wpabuf_len(sta->pending_eapol_rx->buf));
+ }
+ wpabuf_free(sta->pending_eapol_rx->buf);
+ os_free(sta->pending_eapol_rx);
+ sta->pending_eapol_rx = NULL;
+ }
}
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index c774d5c..42b0299 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -861,6 +861,29 @@
}
+static void ieee802_1x_save_eapol(struct sta_info *sta, const u8 *buf,
+ size_t len)
+{
+ if (sta->pending_eapol_rx) {
+ wpabuf_free(sta->pending_eapol_rx->buf);
+ } else {
+ sta->pending_eapol_rx =
+ os_malloc(sizeof(*sta->pending_eapol_rx));
+ if (!sta->pending_eapol_rx)
+ return;
+ }
+
+ sta->pending_eapol_rx->buf = wpabuf_alloc_copy(buf, len);
+ if (!sta->pending_eapol_rx->buf) {
+ os_free(sta->pending_eapol_rx);
+ sta->pending_eapol_rx = NULL;
+ return;
+ }
+
+ os_get_reltime(&sta->pending_eapol_rx->rx_time);
+}
+
+
/**
* ieee802_1x_receive - Process the EAPOL frames from the Supplicant
* @hapd: hostapd BSS data
@@ -891,6 +914,13 @@
!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
"associated/Pre-authenticating STA");
+
+ if (sta && (sta->flags & WLAN_STA_AUTH)) {
+ wpa_printf(MSG_DEBUG, "Saving EAPOL frame from " MACSTR
+ " for later use", MAC2STR(sta->addr));
+ ieee802_1x_save_eapol(sta, buf, len);
+ }
+
return;
}
@@ -1183,6 +1213,12 @@
eloop_cancel_timeout(ieee802_1x_wnm_notif_send, hapd, sta);
#endif /* CONFIG_HS20 */
+ if (sta->pending_eapol_rx) {
+ wpabuf_free(sta->pending_eapol_rx->buf);
+ os_free(sta->pending_eapol_rx);
+ sta->pending_eapol_rx = NULL;
+ }
+
if (sm == NULL)
return;
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index cd89e99..70a59cc 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -56,6 +56,11 @@
u8 channels[];
};
+struct pending_eapol_rx {
+ struct wpabuf *buf;
+ struct os_reltime rx_time;
+};
+
struct sta_info {
struct sta_info *next; /* next entry in sta list */
struct sta_info *hnext; /* next entry in hash table list */
@@ -113,6 +118,8 @@
/* IEEE 802.1X related data */
struct eapol_state_machine *eapol_sm;
+ struct pending_eapol_rx *pending_eapol_rx;
+
u64 acct_session_id;
struct os_reltime acct_session_start;
int acct_session_started;
diff --git a/src/common/ctrl_iface_common.c b/src/common/ctrl_iface_common.c
new file mode 100644
index 0000000..acd2410
--- /dev/null
+++ b/src/common/ctrl_iface_common.c
@@ -0,0 +1,152 @@
+/*
+ * Common hostapd/wpa_supplicant ctrl iface code.
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2015, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <netdb.h>
+#include <sys/un.h>
+
+#include "utils/common.h"
+#include "ctrl_iface_common.h"
+
+static int sockaddr_compare(struct sockaddr_storage *a, socklen_t a_len,
+ struct sockaddr_storage *b, socklen_t b_len)
+{
+ struct sockaddr_in *in_a, *in_b;
+ struct sockaddr_in6 *in6_a, *in6_b;
+ struct sockaddr_un *u_a, *u_b;
+
+ if (a->ss_family != b->ss_family)
+ return 1;
+
+ switch (a->ss_family) {
+ case AF_INET:
+ in_a = (struct sockaddr_in *) a;
+ in_b = (struct sockaddr_in *) b;
+
+ if (in_a->sin_port != in_b->sin_port)
+ return 1;
+ if (in_a->sin_addr.s_addr != in_b->sin_addr.s_addr)
+ return 1;
+ break;
+ case AF_INET6:
+ in6_a = (struct sockaddr_in6 *) a;
+ in6_b = (struct sockaddr_in6 *) b;
+
+ if (in6_a->sin6_port != in6_b->sin6_port)
+ return 1;
+ if (os_memcmp(&in6_a->sin6_addr, &in6_b->sin6_addr,
+ sizeof(in6_a->sin6_addr)) != 0)
+ return 1;
+ break;
+ case AF_UNIX:
+ u_a = (struct sockaddr_un *) a;
+ u_b = (struct sockaddr_un *) b;
+
+ if (a_len != b_len ||
+ os_memcmp(u_a->sun_path, u_b->sun_path,
+ a_len - offsetof(struct sockaddr_un, sun_path))
+ != 0)
+ return 1;
+ break;
+ default:
+ return 1;
+ }
+
+ return 0;
+}
+
+
+void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock,
+ socklen_t socklen)
+{
+ char host[NI_MAXHOST] = { 0 };
+ char service[NI_MAXSERV] = { 0 };
+ char addr_txt[200];
+
+ switch (sock->ss_family) {
+ case AF_INET:
+ case AF_INET6:
+ getnameinfo((struct sockaddr *) sock, socklen,
+ host, sizeof(host),
+ service, sizeof(service),
+ NI_NUMERICHOST);
+
+ wpa_printf(level, "%s %s:%s", msg, host, service);
+ break;
+ case AF_UNIX:
+ printf_encode(addr_txt, sizeof(addr_txt),
+ (u8 *) ((struct sockaddr_un *) sock)->sun_path,
+ socklen - offsetof(struct sockaddr_un, sun_path));
+ wpa_printf(level, "%s %s", msg, addr_txt);
+ break;
+ default:
+ wpa_printf(level, "%s", msg);
+ break;
+ }
+}
+
+
+int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+ socklen_t fromlen)
+{
+ struct wpa_ctrl_dst *dst;
+
+ dst = os_zalloc(sizeof(*dst));
+ if (dst == NULL)
+ return -1;
+ os_memcpy(&dst->addr, from, fromlen);
+ dst->addrlen = fromlen;
+ dst->debug_level = MSG_INFO;
+ dl_list_add(ctrl_dst, &dst->list);
+
+ sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor attached", from, fromlen);
+ return 0;
+}
+
+
+int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+ socklen_t fromlen)
+{
+ struct wpa_ctrl_dst *dst;
+
+ dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
+ if (!sockaddr_compare(from, fromlen,
+ &dst->addr, dst->addrlen)) {
+ sockaddr_print(MSG_DEBUG, "CTRL_IFACE monitor detached",
+ from, fromlen);
+ dl_list_del(&dst->list);
+ os_free(dst);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
+int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+ socklen_t fromlen, const char *level)
+{
+ struct wpa_ctrl_dst *dst;
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
+
+ dl_list_for_each(dst, ctrl_dst, struct wpa_ctrl_dst, list) {
+ if (!sockaddr_compare(from, fromlen,
+ &dst->addr, dst->addrlen)) {
+ sockaddr_print(MSG_DEBUG,
+ "CTRL_IFACE changed monitor level",
+ from, fromlen);
+ dst->debug_level = atoi(level);
+ return 0;
+ }
+ }
+
+ return -1;
+}
diff --git a/src/common/ctrl_iface_common.h b/src/common/ctrl_iface_common.h
new file mode 100644
index 0000000..0b6e3e7
--- /dev/null
+++ b/src/common/ctrl_iface_common.h
@@ -0,0 +1,38 @@
+/*
+ * Common hostapd/wpa_supplicant ctrl iface code.
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2015, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+#ifndef CONTROL_IFACE_COMMON_H
+#define CONTROL_IFACE_COMMON_H
+
+#include "utils/list.h"
+
+/**
+ * struct wpa_ctrl_dst - Data structure of control interface monitors
+ *
+ * This structure is used to store information about registered control
+ * interface monitors into struct wpa_supplicant.
+ */
+struct wpa_ctrl_dst {
+ struct dl_list list;
+ struct sockaddr_storage addr;
+ socklen_t addrlen;
+ int debug_level;
+ int errors;
+};
+
+void sockaddr_print(int level, const char *msg, struct sockaddr_storage *sock,
+ socklen_t socklen);
+
+int ctrl_iface_attach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+ socklen_t fromlen);
+int ctrl_iface_detach(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+ socklen_t fromlen);
+int ctrl_iface_level(struct dl_list *ctrl_dst, struct sockaddr_storage *from,
+ socklen_t fromlen, const char *level);
+
+#endif /* CONTROL_IFACE_COMMON_H */
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index a3ee91d..f3d185e 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -162,6 +162,7 @@
QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE = 109,
/* 110..114 - reserved for QCA */
QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_DECR_DB = 115,
+ /* 116..118 - reserved for QCA */
};
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 570dee6..5fb6652 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -5912,6 +5912,14 @@
params->ifname, master_ifname);
/* start listening for EAPOL on the master interface */
add_ifidx(drv, if_nametoindex(master_ifname), drv->ifindex);
+
+ /* check if master itself is under bridge */
+ if (linux_br_get(master_ifname, master_ifname) == 0) {
+ wpa_printf(MSG_DEBUG, "nl80211: which is in bridge %s",
+ master_ifname);
+ br_ifindex = if_nametoindex(master_ifname);
+ os_strlcpy(bss->brname, master_ifname, IFNAMSIZ);
+ }
} else {
master_ifname[0] = '\0';
}
diff --git a/src/fst/fst_group.c b/src/fst/fst_group.c
index e0c055f..d6157b1 100644
--- a/src/fst/fst_group.c
+++ b/src/fst/fst_group.c
@@ -220,7 +220,7 @@
if (peer_addr &&
fst_iface_is_connected(iface, peer_addr,
- TRUE) &&
+ FALSE) &&
band_id == fst_iface_get_band_id(iface)) {
os_memcpy(iface_peer_addr, peer_addr,
ETH_ALEN);
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index fe0096f..9f0b3f3 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -1268,6 +1268,11 @@
dev->client_timeout = msg.config_timeout[1];
}
+ if (msg.wfd_subelems) {
+ wpabuf_free(dev->info.wfd_subelems);
+ dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
+ }
+
if (!msg.operating_channel && !go) {
/*
* Note: P2P Client may omit Operating Channel attribute to
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index e6535d4..93a0535 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -1349,6 +1349,9 @@
" with no pending request", MAC2STR(sa));
p2p_parse_free(&msg);
return;
+ } else if (msg.wfd_subelems) {
+ wpabuf_free(dev->info.wfd_subelems);
+ dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
}
if (dev->dialog_token != msg.dialog_token) {
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index 2ef4c51..a8bc5ba 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -425,9 +425,16 @@
u8 dialog_token, const struct wpabuf *resp_tlvs)
{
struct wpabuf *resp;
+ size_t max_len;
+
+ /*
+ * In the 60 GHz, we have a smaller maximum frame length for management
+ * frames.
+ */
+ max_len = (freq > 56160) ? 928 : 1400;
/* TODO: fix the length limit to match with the maximum frame length */
- if (wpabuf_len(resp_tlvs) > 1400) {
+ if (wpabuf_len(resp_tlvs) > max_len) {
p2p_dbg(p2p, "SD response long enough to require fragmentation");
if (p2p->sd_resp) {
/*
@@ -614,7 +621,7 @@
{
struct wpabuf *resp;
u8 dialog_token;
- size_t frag_len;
+ size_t frag_len, max_len;
int more = 0;
wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Request", data, len);
@@ -638,9 +645,14 @@
return;
}
+ /*
+ * In the 60 GHz, we have a smaller maximum frame length for management
+ * frames.
+ */
+ max_len = (rx_freq > 56160) ? 928 : 1400;
frag_len = wpabuf_len(p2p->sd_resp) - p2p->sd_resp_pos;
- if (frag_len > 1400) {
- frag_len = 1400;
+ if (frag_len > max_len) {
+ frag_len = max_len;
more = 1;
}
resp = p2p_build_gas_comeback_resp(dialog_token, WLAN_STATUS_SUCCESS,