aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hostapd/config_file.c12
-rw-r--r--src/ap/acs.c2
-rw-r--r--src/ap/ap_drv_ops.c26
-rw-r--r--src/ap/dfs.c85
-rw-r--r--src/ap/hostapd.h3
-rw-r--r--src/ap/hw_features.c92
-rw-r--r--src/ap/ieee802_11_vht.c53
-rw-r--r--src/ap/wpa_auth.c5
-rw-r--r--src/common/ieee802_11_defs.h15
-rw-r--r--src/crypto/dh_groups.c2
-rw-r--r--src/crypto/tls_openssl.c6
-rw-r--r--src/drivers/driver.h7
-rw-r--r--src/drivers/driver_atheros.c4
-rw-r--r--src/drivers/driver_bsd.c2
-rw-r--r--src/drivers/driver_madwifi.c2
-rw-r--r--src/drivers/driver_nl80211.c301
-rw-r--r--src/drivers/driver_wext.c2
-rw-r--r--src/drivers/linux_ioctl.c7
-rw-r--r--src/eap_common/ikev2_common.c6
-rw-r--r--src/p2p/p2p.c85
-rw-r--r--src/p2p/p2p.h45
-rw-r--r--src/p2p/p2p_build.c64
-rw-r--r--src/p2p/p2p_go_neg.c40
-rw-r--r--src/p2p/p2p_i.h14
-rw-r--r--src/p2p/p2p_invitation.c3
-rw-r--r--src/p2p/p2p_utils.c126
-rw-r--r--src/radius/radius.c2
-rw-r--r--src/tls/tlsv1_common.c5
-rw-r--r--src/utils/common.c15
-rw-r--r--src/utils/common.h3
-rw-r--r--src/utils/os.h12
-rw-r--r--src/utils/os_unix.c4
-rw-r--r--src/wps/wps_attr_build.c10
-rw-r--r--wpa_supplicant/Android.mk6
-rw-r--r--wpa_supplicant/Makefile6
-rw-r--r--wpa_supplicant/README-P2P8
-rw-r--r--wpa_supplicant/ap.c32
-rw-r--r--wpa_supplicant/config.c28
-rw-r--r--wpa_supplicant/config.h12
-rw-r--r--wpa_supplicant/config_file.c11
-rw-r--r--wpa_supplicant/config_ssid.h2
-rw-r--r--wpa_supplicant/ctrl_iface.c48
-rw-r--r--wpa_supplicant/ctrl_iface_unix.c1
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.c12
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_p2p.c10
-rw-r--r--wpa_supplicant/dbus/dbus_old_handlers.c10
-rw-r--r--wpa_supplicant/defconfig4
-rw-r--r--wpa_supplicant/interworking.c8
-rw-r--r--wpa_supplicant/p2p_supplicant.c299
-rw-r--r--wpa_supplicant/p2p_supplicant.h10
-rw-r--r--wpa_supplicant/wpa_cli.c8
-rw-r--r--wpa_supplicant/wpa_supplicant.c8
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h1
-rw-r--r--wpa_supplicant/wps_supplicant.c1
54 files changed, 1247 insertions, 338 deletions
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index fdd7504d..0b05ab25 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -1060,15 +1060,15 @@ static int hostapd_config_vht_capab(struct hostapd_config *conf,
if (os_strstr(capab, "[RX-STBC-1234]"))
conf->vht_capab |= VHT_CAP_RXSTBC_4;
if (os_strstr(capab, "[SU-BEAMFORMER]"))
- conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
+ conf->vht_capab |= VHT_CAP_SU_BEAMFORMER_CAPABLE;
if (os_strstr(capab, "[SU-BEAMFORMEE]"))
- conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+ conf->vht_capab |= VHT_CAP_SU_BEAMFORMEE_CAPABLE;
if (os_strstr(capab, "[BF-ANTENNA-2]") &&
- (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE))
- conf->vht_capab |= VHT_CAP_BEAMFORMER_ANTENNAS_MAX;
+ (conf->vht_capab & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
+ conf->vht_capab |= (1 << VHT_CAP_BEAMFORMEE_STS_OFFSET);
if (os_strstr(capab, "[SOUNDING-DIMENSION-2]") &&
- (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE))
- conf->vht_capab |= VHT_CAP_SOUNDING_DIMENTION_MAX;
+ (conf->vht_capab & VHT_CAP_SU_BEAMFORMER_CAPABLE))
+ conf->vht_capab |= (1 << VHT_CAP_SOUNDING_DIMENSION_OFFSET);
if (os_strstr(capab, "[MU-BEAMFORMER]"))
conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
if (os_strstr(capab, "[MU-BEAMFORMEE]"))
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 8536e481..019b334f 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -358,7 +358,7 @@ static int acs_usable_ht40_chan(struct hostapd_channel_data *chan)
157, 184, 192 };
unsigned int i;
- for (i = 0; i < sizeof(allowed) / sizeof(allowed[0]); i++)
+ for (i = 0; i < ARRAY_SIZE(allowed); i++)
if (chan->chan == allowed[i])
return 1;
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 9023eaba..72f582d7 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -467,7 +467,7 @@ static int hostapd_set_freq_params(struct hostapd_freq_params *data, int mode,
int freq, int channel, int ht_enabled,
int vht_enabled, int sec_channel_offset,
int vht_oper_chwidth, int center_segment0,
- int center_segment1)
+ int center_segment1, u32 vht_caps)
{
int tmp;
@@ -494,6 +494,11 @@ static int hostapd_set_freq_params(struct hostapd_freq_params *data, int mode,
return -1;
break;
case VHT_CHANWIDTH_80P80MHZ:
+ if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
+ wpa_printf(MSG_ERROR,
+ "80+80 channel width is not supported!");
+ return -1;
+ }
if (center_segment1 == center_segment0 + 4 ||
center_segment1 == center_segment0 - 4)
return -1;
@@ -517,6 +522,12 @@ static int hostapd_set_freq_params(struct hostapd_freq_params *data, int mode,
break;
case VHT_CHANWIDTH_160MHZ:
data->bandwidth = 160;
+ if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
+ VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
+ wpa_printf(MSG_ERROR,
+ "160MHZ channel width is not supported!");
+ return -1;
+ }
if (center_segment1)
return -1;
if (!sec_channel_offset)
@@ -545,7 +556,8 @@ int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
vht_enabled, sec_channel_offset,
vht_oper_chwidth,
- center_segment0, center_segment1))
+ center_segment0, center_segment1,
+ hapd->iface->current_mode->vht_capab))
return -1;
if (hapd->driver == NULL)
@@ -724,6 +736,7 @@ int hostapd_start_dfs_cac(struct hostapd_data *hapd, int mode, int freq,
int center_segment0, int center_segment1)
{
struct hostapd_freq_params data;
+ int res;
if (!hapd->driver || !hapd->driver->start_dfs_cac)
return 0;
@@ -737,10 +750,15 @@ int hostapd_start_dfs_cac(struct hostapd_data *hapd, int mode, int freq,
if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
vht_enabled, sec_channel_offset,
vht_oper_chwidth, center_segment0,
- center_segment1))
+ center_segment1,
+ hapd->iface->current_mode->vht_capab))
return -1;
- return hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
+ res = hapd->driver->start_dfs_cac(hapd->drv_priv, &data);
+ if (!res)
+ hapd->cac_started = 1;
+
+ return res;
}
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 37bbd203..a30861fa 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -55,13 +55,37 @@ static int dfs_channel_available(struct hostapd_channel_data *chan)
}
-static int dfs_is_ht40_allowed(struct hostapd_channel_data *chan)
+static int dfs_is_chan_allowed(struct hostapd_channel_data *chan, int n_chans)
{
- int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
- 184, 192 };
- unsigned int i;
+ /*
+ * The tables contain first valid channel number based on channel width.
+ * We will also choose this first channel as the control one.
+ */
+ int allowed_40[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
+ 184, 192 };
+ /*
+ * VHT80, valid channels based on center frequency:
+ * 42, 58, 106, 122, 138, 155
+ */
+ int allowed_80[] = { 36, 52, 100, 116, 132, 149 };
+ int *allowed = allowed_40;
+ unsigned int i, allowed_no = 0;
+
+ switch (n_chans) {
+ case 2:
+ allowed = allowed_40;
+ allowed_no = ARRAY_SIZE(allowed_40);
+ break;
+ case 4:
+ allowed = allowed_80;
+ allowed_no = ARRAY_SIZE(allowed_80);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "Unknown width for %d channels", n_chans);
+ break;
+ }
- for (i = 0; i < sizeof(allowed) / sizeof(allowed[0]); i++) {
+ for (i = 0; i < allowed_no; i++) {
if (chan->chan == allowed[i])
return 1;
}
@@ -92,7 +116,7 @@ static int dfs_find_channel(struct hostapd_data *hapd,
/* Skip HT40/VHT uncompatible channels */
if (hapd->iconf->ieee80211n &&
hapd->iconf->secondary_channel) {
- if (!dfs_is_ht40_allowed(chan))
+ if (!dfs_is_chan_allowed(chan, n_chans))
continue;
for (j = 1; j < n_chans; j++) {
@@ -130,7 +154,14 @@ static void dfs_adjust_vht_center_freq(struct hostapd_data *hapd,
switch (hapd->iconf->vht_oper_chwidth) {
case VHT_CHANWIDTH_USE_HT:
- hapd->iconf->vht_oper_centr_freq_seg0_idx = chan->chan + 2;
+ if (hapd->iconf->secondary_channel == 1)
+ hapd->iconf->vht_oper_centr_freq_seg0_idx =
+ chan->chan + 2;
+ else if (hapd->iconf->secondary_channel == -1)
+ hapd->iconf->vht_oper_centr_freq_seg0_idx =
+ chan->chan - 2;
+ else
+ hapd->iconf->vht_oper_centr_freq_seg0_idx = chan->chan;
break;
case VHT_CHANWIDTH_80MHZ:
hapd->iconf->vht_oper_centr_freq_seg0_idx = chan->chan + 6;
@@ -138,6 +169,7 @@ static void dfs_adjust_vht_center_freq(struct hostapd_data *hapd,
case VHT_CHANWIDTH_160MHZ:
hapd->iconf->vht_oper_centr_freq_seg0_idx =
chan->chan + 14;
+ break;
default:
wpa_printf(MSG_INFO, "DFS only VHT20/40/80/160 is supported now");
break;
@@ -385,14 +417,15 @@ static int dfs_are_channels_overlapped(struct hostapd_data *hapd, int freq,
u8 radar_chan;
int res = 0;
- if (hapd->iface->freq == freq)
- res++;
-
/* Our configuration */
mode = hapd->iface->current_mode;
start_chan_idx = dfs_get_start_chan_idx(hapd);
n_chans = dfs_get_used_n_chans(hapd);
+ /* Check we are on DFS channel(s) */
+ if (!dfs_check_chans_radar(hapd, start_chan_idx, n_chans))
+ return 0;
+
/* Reported via radar event */
switch (chan_width) {
case CHAN_WIDTH_20_NOHT:
@@ -422,6 +455,8 @@ static int dfs_are_channels_overlapped(struct hostapd_data *hapd, int freq,
for (i = 0; i < n_chans; i++) {
chan = &mode->channels[start_chan_idx + i];
+ if (!(chan->flag & HOSTAPD_CHAN_RADAR))
+ continue;
for (j = 0; j < radar_n_chans; j++) {
wpa_printf(MSG_DEBUG, "checking our: %d, radar: %d",
chan->chan, radar_chan + j * 4);
@@ -511,29 +546,13 @@ int hostapd_dfs_complete_cac(struct hostapd_data *hapd, int success, int freq,
int ht_enabled, int chan_offset, int chan_width,
int cf1, int cf2)
{
- struct hostapd_channel_data *channel;
- int err = 1;
-
if (success) {
/* Complete iface/ap configuration */
set_dfs_state(hapd, freq, ht_enabled, chan_offset,
chan_width, cf1, cf2,
HOSTAPD_CHAN_DFS_AVAILABLE);
+ hapd->cac_started = 0;
hostapd_setup_interface_complete(hapd->iface, 0);
- } else {
- /* Switch to new channel */
- set_dfs_state(hapd, freq, ht_enabled, chan_offset,
- chan_width, cf1, cf2,
- HOSTAPD_CHAN_DFS_UNAVAILABLE);
- channel = dfs_get_valid_channel(hapd);
- if (channel) {
- hapd->iconf->channel = channel->chan;
- hapd->iface->freq = channel->freq;
- err = 0;
- } else
- wpa_printf(MSG_ERROR, "No valid channel available");
-
- hostapd_setup_interface_complete(hapd->iface, err);
}
return 0;
@@ -553,7 +572,13 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_data *hapd)
err = 0;
}
- hapd->driver->stop_ap(hapd->drv_priv);
+ if (!hapd->cac_started) {
+ wpa_printf(MSG_DEBUG, "DFS radar detected");
+ hapd->driver->stop_ap(hapd->drv_priv);
+ } else {
+ wpa_printf(MSG_DEBUG, "DFS radar detected during CAC");
+ hapd->cac_started = 0;
+ }
hostapd_setup_interface_complete(hapd->iface, err);
return 0;
@@ -579,10 +604,6 @@ int hostapd_dfs_radar_detected(struct hostapd_data *hapd, int freq,
if (!res)
return 0;
- /* we are working on non-DFS channel - skip event */
- if (res == 0)
- return 0;
-
/* radar detected while operating, switch the channel. */
res = hostapd_dfs_start_channel_switch(hapd);
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index dbf1b52f..d79c3e53 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -152,6 +152,9 @@ struct hostapd_data {
int parameter_set_count;
+ /* DFS specific parameters */
+ int cac_started;
+
/* Time Advertisement */
u8 time_update_counter;
struct wpabuf *time_adv;
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 609ed535..d2831d4c 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -270,7 +270,7 @@ static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
first = sec_chan;
ok = 0;
- for (k = 0; k < sizeof(allowed) / sizeof(allowed[0]); k++) {
+ for (k = 0; k < ARRAY_SIZE(allowed); k++) {
if (first == allowed[k]) {
ok = 1;
break;
@@ -653,6 +653,92 @@ static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
return 1;
}
+
+#ifdef CONFIG_IEEE80211AC
+
+static int ieee80211ac_cap_check(u32 hw, u32 conf, u32 cap, const char *name)
+{
+ u32 req_cap = conf & cap;
+
+ /*
+ * Make sure we support all requested capabilities.
+ * NOTE: We assume that 'cap' represents a capability mask,
+ * not a discrete value.
+ */
+ if ((hw & req_cap) != req_cap) {
+ wpa_printf(MSG_ERROR, "Driver does not support configured VHT capability [%s]",
+ name);
+ return 0;
+ }
+ return 1;
+}
+
+
+static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 cap,
+ const char *name)
+{
+ u32 hw_max = hw & cap;
+ u32 conf_val = conf & cap;
+
+ if (conf_val > hw_max) {
+ int offset = find_first_bit(cap);
+ wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)",
+ name, conf_val >> offset, hw_max >> offset);
+ return 0;
+ }
+ return 1;
+}
+
+
+static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
+{
+ u32 hw = iface->current_mode->vht_capab;
+ u32 conf = iface->conf->vht_capab;
+
+ wpa_printf(MSG_DEBUG, "hw vht capab: 0x%x, conf vht capab: 0x%x",
+ hw, conf);
+
+#define VHT_CAP_CHECK(cap) \
+ do { \
+ if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \
+ return 0; \
+ } while (0)
+
+#define VHT_CAP_CHECK_MAX(cap) \
+ do { \
+ if (!ieee80211ac_cap_check_max(hw, conf, cap, #cap)) \
+ return 0; \
+ } while (0)
+
+ VHT_CAP_CHECK_MAX(VHT_CAP_MAX_MPDU_LENGTH_MASK);
+ VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160MHZ);
+ VHT_CAP_CHECK(VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ);
+ VHT_CAP_CHECK(VHT_CAP_RXLDPC);
+ VHT_CAP_CHECK(VHT_CAP_SHORT_GI_80);
+ VHT_CAP_CHECK(VHT_CAP_SHORT_GI_160);
+ VHT_CAP_CHECK(VHT_CAP_TXSTBC);
+ VHT_CAP_CHECK_MAX(VHT_CAP_RXSTBC_MASK);
+ VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMER_CAPABLE);
+ VHT_CAP_CHECK(VHT_CAP_SU_BEAMFORMEE_CAPABLE);
+ VHT_CAP_CHECK_MAX(VHT_CAP_BEAMFORMEE_STS_MAX);
+ VHT_CAP_CHECK_MAX(VHT_CAP_SOUNDING_DIMENSION_MAX);
+ VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMER_CAPABLE);
+ VHT_CAP_CHECK(VHT_CAP_MU_BEAMFORMEE_CAPABLE);
+ VHT_CAP_CHECK(VHT_CAP_VHT_TXOP_PS);
+ VHT_CAP_CHECK(VHT_CAP_HTC_VHT);
+ VHT_CAP_CHECK_MAX(VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT);
+ VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB);
+ VHT_CAP_CHECK(VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB);
+ VHT_CAP_CHECK(VHT_CAP_RX_ANTENNA_PATTERN);
+ VHT_CAP_CHECK(VHT_CAP_TX_ANTENNA_PATTERN);
+
+#undef VHT_CAP_CHECK
+#undef VHT_CAP_CHECK_MAX
+
+ return 1;
+}
+#endif /* CONFIG_IEEE80211AC */
+
#endif /* CONFIG_IEEE80211N */
@@ -664,6 +750,10 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
return 0;
if (!ieee80211n_supported_ht_capab(iface))
return -1;
+#ifdef CONFIG_IEEE80211AC
+ if (!ieee80211ac_supported_vht_capab(iface))
+ return -1;
+#endif /* CONFIG_IEEE80211AC */
ret = ieee80211n_check_40mhz(iface);
if (ret)
return ret;
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 0012c0ff..38590a32 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -113,9 +113,60 @@ void hostapd_get_vht_capab(struct hostapd_data *hapd,
struct ieee80211_vht_capabilities *vht_cap,
struct ieee80211_vht_capabilities *neg_vht_cap)
{
+ u32 cap, own_cap, sym_caps;
+
if (vht_cap == NULL)
return;
os_memcpy(neg_vht_cap, vht_cap, sizeof(*neg_vht_cap));
- /* TODO: mask own capabilities, like get_ht_capab() */
+ cap = le_to_host32(neg_vht_cap->vht_capabilities_info);
+ own_cap = hapd->iconf->vht_capab;
+
+ /* mask out symmetric VHT capabilities we don't support */
+ sym_caps = VHT_CAP_SHORT_GI_80 | VHT_CAP_SHORT_GI_160;
+ cap &= ~sym_caps | (own_cap & sym_caps);
+
+ /* mask out beamformer/beamformee caps if not supported */
+ if (!(own_cap & VHT_CAP_SU_BEAMFORMER_CAPABLE))
+ cap &= ~(VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+ VHT_CAP_BEAMFORMEE_STS_MAX);
+
+ if (!(own_cap & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
+ cap &= ~(VHT_CAP_SU_BEAMFORMER_CAPABLE |
+ VHT_CAP_SOUNDING_DIMENSION_MAX);
+
+ if (!(own_cap & VHT_CAP_MU_BEAMFORMER_CAPABLE))
+ cap &= ~VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+
+ if (!(own_cap & VHT_CAP_MU_BEAMFORMEE_CAPABLE))
+ cap &= ~VHT_CAP_MU_BEAMFORMER_CAPABLE;
+
+ /* mask channel widths we don't support */
+ switch (own_cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
+ case VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
+ break;
+ case VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
+ if (cap & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) {
+ cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+ cap |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+ }
+ break;
+ default:
+ cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK;
+ break;
+ }
+
+ if (!(cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK))
+ cap &= ~VHT_CAP_SHORT_GI_160;
+
+ /*
+ * if we don't support RX STBC, mask out TX STBC in the STA's HT caps
+ * if we don't support TX STBC, mask out RX STBC in the STA's HT caps
+ */
+ if (!(own_cap & VHT_CAP_RXSTBC_MASK))
+ cap &= ~VHT_CAP_TXSTBC;
+ if (!(own_cap & VHT_CAP_TXSTBC))
+ cap &= ~VHT_CAP_RXSTBC_MASK;
+
+ neg_vht_cap->vht_capabilities_info = host_to_le32(cap);
}
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 0286c5b8..03b15c24 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1863,6 +1863,7 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
{
struct wpa_igtk_kde igtk;
struct wpa_group *gsm = sm->group;
+ u8 rsc[WPA_KEY_RSC_LEN];
if (!sm->mgmt_frame_prot)
return pos;
@@ -1870,8 +1871,10 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
igtk.keyid[0] = gsm->GN_igtk;
igtk.keyid[1] = 0;
if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
- wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, igtk.pn) < 0)
+ wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, rsc) < 0)
os_memset(igtk.pn, 0, sizeof(igtk.pn));
+ else
+ os_memcpy(igtk.pn, rsc, sizeof(igtk.pn));
os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
if (sm->wpa_auth->conf.disable_gtk) {
/*
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index ca38701b..8ce1bfb2 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -704,8 +704,10 @@ struct ieee80211_vht_operation {
/* VHT Defines */
#define VHT_CAP_MAX_MPDU_LENGTH_7991 ((u32) BIT(0))
#define VHT_CAP_MAX_MPDU_LENGTH_11454 ((u32) BIT(1))
+#define VHT_CAP_MAX_MPDU_LENGTH_MASK ((u32) BIT(0) | BIT(1))
#define VHT_CAP_SUPP_CHAN_WIDTH_160MHZ ((u32) BIT(2))
#define VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ ((u32) BIT(3))
+#define VHT_CAP_SUPP_CHAN_WIDTH_MASK ((u32) BIT(2) | BIT(3))
#define VHT_CAP_RXLDPC ((u32) BIT(4))
#define VHT_CAP_SHORT_GI_80 ((u32) BIT(5))
#define VHT_CAP_SHORT_GI_160 ((u32) BIT(6))
@@ -714,15 +716,22 @@ struct ieee80211_vht_operation {
#define VHT_CAP_RXSTBC_2 ((u32) BIT(9))
#define VHT_CAP_RXSTBC_3 ((u32) BIT(8) | BIT(9))
#define VHT_CAP_RXSTBC_4 ((u32) BIT(10))
+#define VHT_CAP_RXSTBC_MASK ((u32) BIT(8) | BIT(9) | \
+ BIT(10))
#define VHT_CAP_SU_BEAMFORMER_CAPABLE ((u32) BIT(11))
#define VHT_CAP_SU_BEAMFORMEE_CAPABLE ((u32) BIT(12))
-#define VHT_CAP_BEAMFORMER_ANTENNAS_MAX ((u32) BIT(13) | BIT(14))
-#define VHT_CAP_SOUNDING_DIMENTION_MAX ((u32) BIT(16) | BIT(17))
+#define VHT_CAP_BEAMFORMEE_STS_MAX ((u32) BIT(13) | \
+ BIT(14) | BIT(15))
+#define VHT_CAP_BEAMFORMEE_STS_OFFSET 13
+#define VHT_CAP_SOUNDING_DIMENSION_MAX ((u32) BIT(16) | \
+ BIT(17) | BIT(18))
+#define VHT_CAP_SOUNDING_DIMENSION_OFFSET 16
#define VHT_CAP_MU_BEAMFORMER_CAPABLE ((u32) BIT(19))
#define VHT_CAP_MU_BEAMFORMEE_CAPABLE ((u32) BIT(20))
#define VHT_CAP_VHT_TXOP_PS ((u32) BIT(21))
#define VHT_CAP_HTC_VHT ((u32) BIT(22))
-#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT ((u32) BIT(23))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT ((u32) BIT(23) | \
+ BIT(24) | BIT(25))
#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB ((u32) BIT(27))
#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB ((u32) BIT(26) | BIT(27))
#define VHT_CAP_RX_ANTENNA_PATTERN ((u32) BIT(28))
diff --git a/src/crypto/dh_groups.c b/src/crypto/dh_groups.c
index 3a675df1..58e94c39 100644
--- a/src/crypto/dh_groups.c
+++ b/src/crypto/dh_groups.c
@@ -1169,7 +1169,7 @@ static struct dh_group dh_groups[] = {
#endif /* ALL_DH_GROUPS */
};
-#define NUM_DH_GROUPS (sizeof(dh_groups) / sizeof(dh_groups[0]))
+#define NUM_DH_GROUPS ARRAY_SIZE(dh_groups)
const struct dh_group * dh_groups_get(int id)
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 48c48760..cb4f56fc 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -798,11 +798,13 @@ void * tls_init(const struct tls_config *conf)
ssl = SSL_CTX_new(TLSv1_method());
if (ssl == NULL) {
tls_openssl_ref_count--;
+#ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
+ if (context != tls_global)
+ os_free(context);
+#endif /* OPENSSL_SUPPORTS_CTX_APP_DATA */
if (tls_openssl_ref_count == 0) {
os_free(tls_global);
tls_global = NULL;
- } else if (context != tls_global) {
- os_free(context);
}
return NULL;
}
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index fd75cd2d..01903f9e 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -37,6 +37,11 @@
#define HOSTAPD_CHAN_DFS_AVAILABLE 0x00000300
#define HOSTAPD_CHAN_DFS_MASK 0x00000300
+#define HOSTAPD_CHAN_VHT_10_70 0x00000800
+#define HOSTAPD_CHAN_VHT_30_50 0x00001000
+#define HOSTAPD_CHAN_VHT_50_30 0x00002000
+#define HOSTAPD_CHAN_VHT_70_10 0x00004000
+
/**
* struct hostapd_channel_data - Channel information
*/
@@ -57,7 +62,7 @@ struct hostapd_channel_data {
int flag;
/**
- * max_tx_power - Maximum transmit power in dBm
+ * max_tx_power - Regulatory transmit power limit in dBm
*/
u8 max_tx_power;
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 2921afb7..2547a43d 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -894,7 +894,7 @@ static int atheros_set_qos_map(void *ctx, const u8 *qos_map_set,
memset(&req, 0, sizeof(struct ieee80211req_athdbg));
req.cmd = IEEE80211_DBGREQ_SETQOSMAPCONF;
os_memset(&iwr, 0, sizeof(iwr));
- os_strncpy(iwr.ifr_name, drv->iface, sizeof(iwr.ifr_name));
+ os_strlcpy(iwr.ifr_name, drv->iface, sizeof(iwr.ifr_name));
iwr.u.data.pointer = (void *) &req;
iwr.u.data.length = sizeof(struct ieee80211req_athdbg);
}
@@ -1385,7 +1385,7 @@ static void fetch_pending_big_events(struct atheros_driver_data *drv)
while (1) {
os_memset(&iwr, 0, sizeof(iwr));
- os_strncpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
iwr.u.data.pointer = (void *) tbuf;
iwr.u.data.length = sizeof(tbuf);
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 4acb12be..45d6b191 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -72,7 +72,7 @@ get80211opmode(struct bsd_driver_data *drv)
struct ifmediareq ifmr;
(void) memset(&ifmr, 0, sizeof(ifmr));
- (void) strncpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
+ (void) os_strlcpy(ifmr.ifm_name, drv->ifname, sizeof(ifmr.ifm_name));
if (ioctl(drv->sock, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0) {
if (ifmr.ifm_current & IFM_IEEE80211_ADHOC) {
diff --git a/src/drivers/driver_madwifi.c b/src/drivers/driver_madwifi.c
index bb48011d..d3379270 100644
--- a/src/drivers/driver_madwifi.c
+++ b/src/drivers/driver_madwifi.c
@@ -182,7 +182,7 @@ set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len)
#endif /* MADWIFI_NG */
int idx = op - first;
if (first <= op &&
- idx < (int) (sizeof(opnames) / sizeof(opnames[0])) &&
+ idx < (int) ARRAY_SIZE(opnames) &&
opnames[idx])
perror(opnames[idx]);
else
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 508022f4..704bc797 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -140,6 +140,31 @@ static void nl_destroy_handles(struct nl_handle **handle)
}
+#if __WORDSIZE == 64
+#define ELOOP_SOCKET_INVALID (intptr_t) 0x8888888888888889ULL
+#else
+#define ELOOP_SOCKET_INVALID (intptr_t) 0x88888889ULL
+#endif
+
+static void nl80211_register_eloop_read(struct nl_handle **handle,
+ eloop_sock_handler handler,
+ void *eloop_data)
+{
+ nl_socket_set_nonblocking(*handle);
+ eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
+ eloop_data, *handle);
+ *handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID);
+}
+
+
+static void nl80211_destroy_eloop_handle(struct nl_handle **handle)
+{
+ *handle = (void *) (((intptr_t) *handle) ^ ELOOP_SOCKET_INVALID);
+ eloop_unregister_read_sock(nl_socket_get_fd(*handle));
+ nl_destroy_handles(handle);
+}
+
+
#ifndef IFF_LOWER_UP
#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
#endif
@@ -580,8 +605,14 @@ static int send_and_recv(struct nl80211_global *global,
nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
valid_handler, valid_data);
- while (err > 0)
- nl_recvmsgs(nl_handle, cb);
+ while (err > 0) {
+ int res = nl_recvmsgs(nl_handle, cb);
+ if (res) {
+ wpa_printf(MSG_INFO,
+ "nl80211: %s->nl_recvmsgs failed: %d",
+ __func__, res);
+ }
+ }
out:
nl_cb_put(cb);
nlmsg_free(msg);
@@ -834,10 +865,15 @@ nla_put_failure:
static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
{
struct nl80211_wiphy_data *w = eloop_ctx;
+ int res;
wpa_printf(MSG_EXCESSIVE, "nl80211: Beacon event message available");
- nl_recvmsgs(handle, w->nl_cb);
+ res = nl_recvmsgs(handle, w->nl_cb);
+ if (res) {
+ wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
+ __func__, res);
+ }
}
@@ -921,8 +957,7 @@ nl80211_get_wiphy_data_ap(struct i802_bss *bss)
return NULL;
}
- eloop_register_read_sock(nl_socket_get_fd(w->nl_beacons),
- nl80211_recv_beacons, w, w->nl_beacons);
+ nl80211_register_eloop_read(&w->nl_beacons, nl80211_recv_beacons, w);
dl_list_add(&nl80211_wiphys, &w->list);
@@ -969,10 +1004,9 @@ static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
if (!dl_list_empty(&w->bsss))
return;
- eloop_unregister_read_sock(nl_socket_get_fd(w->nl_beacons));
+ nl80211_destroy_eloop_handle(&w->nl_beacons);
nl_cb_put(w->nl_cb);
- nl_destroy_handles(&w->nl_beacons);
dl_list_del(&w->list);
os_free(w);
}
@@ -1845,8 +1879,6 @@ static void mlme_event_michael_mic_failure(struct i802_bss *bss,
static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
struct nlattr *tb[])
{
- u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
-
if (tb[NL80211_ATTR_MAC] == NULL) {
wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
"event");
@@ -1854,10 +1886,6 @@ static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
}
os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
- /* register for any AUTH message */
- nl80211_register_frame(&drv->first_bss, drv->first_bss.nl_mgmt,
- type, NULL, 0);
-
drv->associated = 1;
wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined",
MAC2STR(drv->bssid));
@@ -2868,10 +2896,15 @@ static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
void *handle)
{
struct nl_cb *cb = eloop_ctx;
+ int res;
wpa_printf(MSG_MSGDUMP, "nl80211: Event message available");
- nl_recvmsgs(handle, cb);
+ res = nl_recvmsgs(handle, cb);
+ if (res) {
+ wpa_printf(MSG_INFO, "nl80211: %s->nl_recvmsgs failed: %d",
+ __func__, res);
+ }
}
@@ -3202,7 +3235,7 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
genlmsg_attrlen(gnlh, 0), NULL);
if (tb[NL80211_ATTR_WIPHY_NAME])
- os_strncpy(drv->phyname,
+ os_strlcpy(drv->phyname,
nla_get_string(tb[NL80211_ATTR_WIPHY_NAME]),
sizeof(drv->phyname));
if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
@@ -3520,9 +3553,9 @@ static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
process_global_event, global);
- eloop_register_read_sock(nl_socket_get_fd(global->nl_event),
- wpa_driver_nl80211_event_receive,
- global->nl_cb, global->nl_event);
+ nl80211_register_eloop_read(&global->nl_event,
+ wpa_driver_nl80211_event_receive,
+ global->nl_cb);
return 0;
@@ -3803,14 +3836,18 @@ static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
if (bss->nl_mgmt == NULL)
return -1;
- eloop_register_read_sock(nl_socket_get_fd(bss->nl_mgmt),
- wpa_driver_nl80211_event_receive, bss->nl_cb,
- bss->nl_mgmt);
-
return 0;
}
+static void nl80211_mgmt_handle_register_eloop(struct i802_bss *bss)
+{
+ nl80211_register_eloop_read(&bss->nl_mgmt,
+ wpa_driver_nl80211_event_receive,
+ bss->nl_cb);
+}
+
+
static int nl80211_register_action_frame(struct i802_bss *bss,
const u8 *match, size_t match_len)
{
@@ -3829,6 +3866,13 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
"handle %p", bss->nl_mgmt);
+ if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
+ u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_AUTH << 4);
+
+ /* register for any AUTH message */
+ nl80211_register_frame(bss, bss->nl_mgmt, type, NULL, 0);
+ }
+
#ifdef CONFIG_INTERWORKING
/* QoS Map Configure */
if (nl80211_register_action_frame(bss, (u8 *) "\x01\x04", 2) < 0)
@@ -3888,6 +3932,8 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x11", 2) < 0)
return -1;
+ nl80211_mgmt_handle_register_eloop(bss);
+
return 0;
}
@@ -3945,7 +3991,7 @@ static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
"handle %p", bss->nl_mgmt);
- for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) {
+ for (i = 0; i < ARRAY_SIZE(stypes); i++) {
if (nl80211_register_frame(bss, bss->nl_mgmt,
(WLAN_FC_TYPE_MGMT << 2) |
(stypes[i] << 4),
@@ -3960,10 +4006,10 @@ static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
if (nl80211_get_wiphy_data_ap(bss) == NULL)
goto out_err;
+ nl80211_mgmt_handle_register_eloop(bss);
return 0;
out_err:
- eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
nl_destroy_handles(&bss->nl_mgmt);
return -1;
}
@@ -3982,10 +4028,10 @@ static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
NULL, 0) < 0)
goto out_err;
+ nl80211_mgmt_handle_register_eloop(bss);
return 0;
out_err:
- eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
nl_destroy_handles(&bss->nl_mgmt);
return -1;
}
@@ -3997,8 +4043,7 @@ static void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason)
return;
wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
"(%s)", bss->nl_mgmt, reason);
- eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
- nl_destroy_handles(&bss->nl_mgmt);
+ nl80211_destroy_eloop_handle(&bss->nl_mgmt);
nl80211_put_wiphy_data_ap(bss);
}
@@ -4028,7 +4073,7 @@ static void nl80211_del_p2pdev(struct i802_bss *bss)
wpa_printf(MSG_DEBUG, "nl80211: Delete P2P Device %s (0x%llx): %s",
bss->ifname, (long long unsigned int) bss->wdev_id,
- strerror(ret));
+ strerror(-ret));
nla_put_failure:
nlmsg_free(msg);
@@ -4058,7 +4103,7 @@ static int nl80211_set_p2pdev(struct i802_bss *bss, int start)
wpa_printf(MSG_DEBUG, "nl80211: %s P2P Device %s (0x%llx): %s",
start ? "Start" : "Stop",
bss->ifname, (long long unsigned int) bss->wdev_id,
- strerror(ret));
+ strerror(-ret));
nla_put_failure:
nlmsg_free(msg);
@@ -5624,10 +5669,6 @@ static void phy_info_freq(struct hostapd_hw_modes *mode,
if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
chan->flag |= HOSTAPD_CHAN_RADAR;
- if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
- !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
- chan->max_tx_power = nla_get_u32(
- tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]) {
enum nl80211_dfs_state state =
nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_DFS_STATE]);
@@ -5950,6 +5991,38 @@ static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start,
}
+static void nl80211_reg_rule_max_eirp(struct nlattr *tb[],
+ struct phy_info_arg *results)
+{
+ u32 start, end, max_eirp;
+ u16 m;
+
+ if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+ tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+ tb[NL80211_ATTR_POWER_RULE_MAX_EIRP] == NULL)
+ return;
+
+ start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+ end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+ max_eirp = nla_get_u32(tb[NL80211_ATTR_POWER_RULE_MAX_EIRP]) / 100;
+
+ wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u mBm",
+ start, end, max_eirp);
+
+ for (m = 0; m < *results->num_modes; m++) {
+ int c;
+ struct hostapd_hw_modes *mode = &results->modes[m];
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+ if ((u32) chan->freq - 10 >= start &&
+ (u32) chan->freq + 10 <= end)
+ chan->max_tx_power = max_eirp;
+ }
+ }
+}
+
+
static void nl80211_reg_rule_ht40(struct nlattr *tb[],
struct phy_info_arg *results)
{
@@ -6006,6 +6079,59 @@ static void nl80211_reg_rule_sec(struct nlattr *tb[],
}
+static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start,
+ int end)
+{
+ int c;
+
+ for (c = 0; c < mode->num_channels; c++) {
+ struct hostapd_channel_data *chan = &mode->channels[c];
+ if (chan->freq - 10 >= start && chan->freq + 70 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_10_70;
+
+ if (chan->freq - 30 >= start && chan->freq + 50 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_30_50;
+
+ if (chan->freq - 50 >= start && chan->freq + 30 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_50_30;
+
+ if (chan->freq - 70 >= start && chan->freq + 10 <= end)
+ chan->flag |= HOSTAPD_CHAN_VHT_70_10;
+ }
+}
+
+
+static void nl80211_reg_rule_vht(struct nlattr *tb[],
+ struct phy_info_arg *results)
+{
+ u32 start, end, max_bw;
+ u16 m;
+
+ if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+ tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+ tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
+ return;
+
+ start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+ end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+ max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+
+ if (max_bw < 80)
+ return;
+
+ for (m = 0; m < *results->num_modes; m++) {
+ if (!(results->modes[m].ht_capab &
+ HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+ continue;
+ /* TODO: use a real VHT support indication */
+ if (!results->modes[m].vht_capab)
+ continue;
+
+ nl80211_set_vht_mode(&results->modes[m], start, end);
+ }
+}
+
+
static int nl80211_get_reg(struct nl_msg *msg, void *arg)
{
struct phy_info_arg *results = arg;
@@ -6040,6 +6166,7 @@ static int nl80211_get_reg(struct nl_msg *msg, void *arg)
nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
nla_data(nl_rule), nla_len(nl_rule), reg_policy);
nl80211_reg_rule_ht40(tb_rule, results);
+ nl80211_reg_rule_max_eirp(tb_rule, results);
}
nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
@@ -6049,12 +6176,19 @@ static int nl80211_get_reg(struct nl_msg *msg, void *arg)
nl80211_reg_rule_sec(tb_rule, results);
}
+ nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+ {
+ nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+ nl80211_reg_rule_vht(tb_rule, results);
+ }
+
return NL_SKIP;
}
-static int nl80211_set_ht40_flags(struct wpa_driver_nl80211_data *drv,
- struct phy_info_arg *results)
+static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv,
+ struct phy_info_arg *results)
{
struct nl_msg *msg;
@@ -6097,7 +6231,7 @@ wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
- nl80211_set_ht40_flags(drv, &result);
+ nl80211_set_regulatory_flags(drv, &result);
return wpa_driver_nl80211_postprocess_modes(result.modes,
num_modes);
}
@@ -7053,12 +7187,13 @@ static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
len = recv(sock, buf, sizeof(buf), 0);
if (len < 0) {
- perror("recv");
+ wpa_printf(MSG_ERROR, "nl80211: Monitor socket recv failed: %s",
+ strerror(errno));
return;
}
if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) {
- printf("received invalid radiotap frame\n");
+ wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame");
return;
}
@@ -7067,7 +7202,8 @@ static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
if (ret == -ENOENT)
break;
if (ret) {
- printf("received invalid radiotap frame (%d)\n", ret);
+ wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame (%d)",
+ ret);
return;
}
switch (iter.this_arg_index) {
@@ -7217,7 +7353,7 @@ static struct sock_filter msock_filter_insns[] = {
};
static struct sock_fprog msock_filter = {
- .len = sizeof(msock_filter_insns)/sizeof(msock_filter_insns[0]),
+ .len = ARRAY_SIZE(msock_filter_insns),
.filter = msock_filter_insns,
};
@@ -7252,7 +7388,8 @@ static int add_monitor_filter(int s)
if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
&msock_filter, sizeof(msock_filter))) {
- perror("SO_ATTACH_FILTER");
+ wpa_printf(MSG_ERROR, "nl80211: setsockopt(SO_ATTACH_FILTER) failed: %s",
+ strerror(errno));
return -1;
}
@@ -7334,7 +7471,8 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
ll.sll_ifindex = drv->monitor_ifidx;
drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (drv->monitor_sock < 0) {
- perror("socket[PF_PACKET,SOCK_RAW]");
+ wpa_printf(MSG_ERROR, "nl80211: socket[PF_PACKET,SOCK_RAW] failed: %s",
+ strerror(errno));
goto error;
}
@@ -7345,7 +7483,8 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
}
if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
- perror("monitor socket bind");
+ wpa_printf(MSG_ERROR, "nl80211: monitor socket bind failed: %s",
+ strerror(errno));
goto error;
}
@@ -7353,13 +7492,14 @@ nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
optval = 20;
if (setsockopt
(drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
- perror("Failed to set socket priority");
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set socket priority: %s",
+ strerror(errno));
goto error;
}
if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
drv, NULL)) {
- printf("Could not register monitor read socket\n");
+ wpa_printf(MSG_INFO, "nl80211: Could not register monitor read socket");
goto error;
}
@@ -7488,8 +7628,8 @@ static int wpa_driver_nl80211_hapd_send_eapol(
data_len;
hdr = os_zalloc(len);
if (hdr == NULL) {
- printf("malloc() failed for i802_send_data(len=%lu)\n",
- (unsigned long) len);
+ wpa_printf(MSG_INFO, "nl80211: Failed to allocate EAPOL buffer(len=%lu)",
+ (unsigned long) len);
return -1;
}
@@ -8888,7 +9028,8 @@ static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
len = recvfrom(sock, buf, sizeof(buf), 0,
(struct sockaddr *)&lladdr, &fromlen);
if (len < 0) {
- perror("recv");
+ wpa_printf(MSG_ERROR, "nl80211: EAPOL recv failed: %s",
+ strerror(errno));
return;
}
@@ -9021,13 +9162,14 @@ static void *i802_init(struct hostapd_data *hapd,
drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
if (drv->eapol_sock < 0) {
- perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)");
+ wpa_printf(MSG_ERROR, "nl80211: socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE) failed: %s",
+ strerror(errno));
goto failed;
}
if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
{
- printf("Could not register read socket for eapol\n");
+ wpa_printf(MSG_INFO, "nl80211: Could not register read socket for eapol");
goto failed;
}
@@ -9154,15 +9296,6 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
struct i802_bss *bss = priv;
struct wpa_driver_nl80211_data *drv = bss->drv;
int ifidx;
-#ifdef HOSTAPD
- struct i802_bss *new_bss = NULL;
-
- if (type == WPA_IF_AP_BSS) {
- new_bss = os_zalloc(sizeof(*new_bss));
- if (new_bss == NULL)
- return -1;
- }
-#endif /* HOSTAPD */
if (addr)
os_memcpy(if_addr, addr, ETH_ALEN);
@@ -9191,9 +9324,6 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
ifidx = nl80211_create_iface(drv, ifname, nlmode, addr,
0, NULL, NULL);
if (ifidx < 0) {
-#ifdef HOSTAPD
- os_free(new_bss);
-#endif /* HOSTAPD */
return -1;
}
}
@@ -9238,16 +9368,23 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
#endif /* CONFIG_P2P */
#ifdef HOSTAPD
- if (bridge &&
- i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
- wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
- "interface %s to a bridge %s", ifname, bridge);
- nl80211_remove_iface(drv, ifidx);
- os_free(new_bss);
- return -1;
- }
-
if (type == WPA_IF_AP_BSS) {
+ struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
+ if (new_bss == NULL) {
+ nl80211_remove_iface(drv, ifidx);
+ return -1;
+ }
+
+ if (bridge &&
+ i802_check_bridge(drv, new_bss, bridge, ifname) < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
+ "interface %s to a bridge %s",
+ ifname, bridge);
+ nl80211_remove_iface(drv, ifidx);
+ os_free(new_bss);
+ return -1;
+ }
+
if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
{
nl80211_remove_iface(drv, ifidx);
@@ -9578,9 +9715,7 @@ static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
} else if (bss->nl_preq) {
wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
"reporting nl_preq=%p", bss->nl_preq);
- eloop_unregister_read_sock(
- nl_socket_get_fd(bss->nl_preq));
- nl_destroy_handles(&bss->nl_preq);
+ nl80211_destroy_eloop_handle(&bss->nl_preq);
}
return 0;
}
@@ -9603,9 +9738,9 @@ static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report)
NULL, 0) < 0)
goto out_err;
- eloop_register_read_sock(nl_socket_get_fd(bss->nl_preq),
- wpa_driver_nl80211_event_receive, bss->nl_cb,
- bss->nl_preq);
+ nl80211_register_eloop_read(&bss->nl_preq,
+ wpa_driver_nl80211_event_receive,
+ bss->nl_cb);
return 0;
@@ -10016,7 +10151,8 @@ static void * nl80211_global_init(void)
global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (global->ioctl_sock < 0) {
- perror("socket(PF_INET,SOCK_DGRAM)");
+ wpa_printf(MSG_ERROR, "nl80211: socket(PF_INET,SOCK_DGRAM) failed: %s",
+ strerror(errno));
goto err;
}
@@ -10044,11 +10180,8 @@ static void nl80211_global_deinit(void *priv)
nl_destroy_handles(&global->nl);
- if (global->nl_event) {
- eloop_unregister_read_sock(
- nl_socket_get_fd(global->nl_event));
- nl_destroy_handles(&global->nl_event);
- }
+ if (global->nl_event)
+ nl80211_destroy_eloop_handle(&global->nl_event);
nl_cb_put(global->nl_cb);
@@ -10711,7 +10844,7 @@ static int android_pno_start(struct i802_bss *bss,
memset(&ifr, 0, sizeof(ifr));
memset(&priv_cmd, 0, sizeof(priv_cmd));
- os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+ os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
priv_cmd.buf = buf;
priv_cmd.used_len = bp;
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 14010502..6e2e771b 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -2427,7 +2427,7 @@ static int wext_sched_scan(void *priv, struct wpa_driver_scan_params *params,
bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
os_memset(&iwr, 0, sizeof(iwr));
- os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
iwr.u.data.pointer = buf;
iwr.u.data.length = bp;
diff --git a/src/drivers/linux_ioctl.c b/src/drivers/linux_ioctl.c
index 4380428f..837971d2 100644
--- a/src/drivers/linux_ioctl.c
+++ b/src/drivers/linux_ioctl.c
@@ -204,11 +204,14 @@ int linux_br_del_if(int sock, const char *brname, const char *ifname)
int linux_br_get(char *brname, const char *ifname)
{
char path[128], brlink[128], *pos;
+ ssize_t res;
+
os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/bridge",
ifname);
- os_memset(brlink, 0, sizeof(brlink));
- if (readlink(path, brlink, sizeof(brlink) - 1) < 0)
+ res = readlink(path, brlink, sizeof(brlink));
+ if (res < 0 || (size_t) res >= sizeof(brlink))
return -1;
+ brlink[res] = '\0';
pos = os_strrchr(brlink, '/');
if (pos == NULL)
return -1;
diff --git a/src/eap_common/ikev2_common.c b/src/eap_common/ikev2_common.c
index 376fcadb..f061866a 100644
--- a/src/eap_common/ikev2_common.c
+++ b/src/eap_common/ikev2_common.c
@@ -21,7 +21,7 @@ static struct ikev2_integ_alg ikev2_integ_algs[] = {
{ AUTH_HMAC_MD5_96, 16, 12 }
};
-#define NUM_INTEG_ALGS (sizeof(ikev2_integ_algs) / sizeof(ikev2_integ_algs[0]))
+#define NUM_INTEG_ALGS ARRAY_SIZE(ikev2_integ_algs)
static struct ikev2_prf_alg ikev2_prf_algs[] = {
@@ -29,7 +29,7 @@ static struct ikev2_prf_alg ikev2_prf_algs[] = {
{ PRF_HMAC_MD5, 16, 16 }
};
-#define NUM_PRF_ALGS (sizeof(ikev2_prf_algs) / sizeof(ikev2_prf_algs[0]))
+#define NUM_PRF_ALGS ARRAY_SIZE(ikev2_prf_algs)
static struct ikev2_encr_alg ikev2_encr_algs[] = {
@@ -37,7 +37,7 @@ static struct ikev2_encr_alg ikev2_encr_algs[] = {
{ ENCR_3DES, 24, 8 }
};
-#define NUM_ENCR_ALGS (sizeof(ikev2_encr_algs) / sizeof(ikev2_encr_algs[0]))
+#define NUM_ENCR_ALGS ARRAY_SIZE(ikev2_encr_algs)
const struct ikev2_integ_alg * ikev2_get_integ(int id)
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 64ca006d..723e4002 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -1208,19 +1208,21 @@ void p2p_stop_find(struct p2p_data *p2p)
static int p2p_prepare_channel_pref(struct p2p_data *p2p,
unsigned int force_freq,
- unsigned int pref_freq)
+ unsigned int pref_freq, int go)
{
u8 op_class, op_channel;
unsigned int freq = force_freq ? force_freq : pref_freq;
- p2p_dbg(p2p, "Prepare channel pref - force_freq=%u pref_freq=%u",
- force_freq, pref_freq);
+ p2p_dbg(p2p, "Prepare channel pref - force_freq=%u pref_freq=%u go=%d",
+ force_freq, pref_freq, go);
if (p2p_freq_to_channel(freq, &op_class, &op_channel) < 0) {
p2p_dbg(p2p, "Unsupported frequency %u MHz", freq);
return -1;
}
- if (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel)) {
+ if (!p2p_channels_includes(&p2p->cfg->channels, op_class, op_channel) &&
+ (go || !p2p_channels_includes(&p2p->cfg->cli_channels, op_class,
+ op_channel))) {
p2p_dbg(p2p, "Frequency %u MHz (oper_class %u channel %u) not allowed for P2P",
freq, op_class, op_channel);
return -1;
@@ -1294,6 +1296,7 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
* @dev: Selected peer device
* @force_freq: Forced frequency in MHz or 0 if not forced
* @pref_freq: Preferred frequency in MHz or 0 if no preference
+ * @go: Whether the local end will be forced to be GO
* Returns: 0 on success, -1 on failure (channel not supported for P2P)
*
* This function is used to do initial operating channel selection for GO
@@ -1302,16 +1305,25 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p)
* is available.
*/
int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
- unsigned int force_freq, unsigned int pref_freq)
+ unsigned int force_freq, unsigned int pref_freq, int go)
{
- p2p_dbg(p2p, "Prepare channel - force_freq=%u pref_freq=%u",
- force_freq, pref_freq);
+ p2p_dbg(p2p, "Prepare channel - force_freq=%u pref_freq=%u go=%d",
+ force_freq, pref_freq, go);
if (force_freq || pref_freq) {
- if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq) < 0)
+ if (p2p_prepare_channel_pref(p2p, force_freq, pref_freq, go) <
+ 0)
return -1;
} else {
p2p_prepare_channel_best(p2p);
}
+ p2p_channels_dump(p2p, "prepared channels", &p2p->channels);
+ if (go)
+ p2p_channels_remove_freqs(&p2p->channels, &p2p->no_go_freq);
+ else if (!force_freq)
+ p2p_channels_union(&p2p->channels, &p2p->cfg->cli_channels,
+ &p2p->channels);
+ p2p_channels_dump(p2p, "after go/cli filter/add", &p2p->channels);
+
p2p_dbg(p2p, "Own preference for operation channel: Operating Class %u Channel %u%s",
p2p->op_reg_class, p2p->op_channel,
force_freq ? " (forced)" : "");
@@ -1367,7 +1379,8 @@ int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
return -1;
}
- if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+ if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq,
+ go_intent == 15) < 0)
return -1;
if (dev->flags & P2P_DEV_GROUP_CLIENT_ONLY) {
@@ -1477,7 +1490,8 @@ int p2p_authorize(struct p2p_data *p2p, const u8 *peer_addr,
return -1;
}
- if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+ if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq, go_intent ==
+ 15) < 0)
return -1;
p2p->ssid_set = 0;
@@ -1618,8 +1632,15 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer)
}
}
+ p2p_channels_dump(p2p, "own channels", &p2p->channels);
+ p2p_channels_dump(p2p, "peer channels", &peer->channels);
p2p_channels_intersect(&p2p->channels, &peer->channels,
&intersection);
+ if (go) {
+ p2p_channels_remove_freqs(&intersection, &p2p->no_go_freq);
+ p2p_channels_dump(p2p, "intersection after no-GO removal",
+ &intersection);
+ }
freqs = 0;
for (i = 0; i < intersection.reg_classes; i++) {
struct p2p_reg_class *c = &intersection.reg_class[i];
@@ -1979,7 +2000,11 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p)
pw_id = p2p_wps_method_pw_id(p2p->go_neg_peer->wps_method);
}
- p2p_build_wps_ie(p2p, buf, pw_id, 1);
+ if (p2p_build_wps_ie(p2p, buf, pw_id, 1) < 0) {
+ p2p_dbg(p2p, "Failed to build WPS IE for Probe Response");
+ wpabuf_free(buf);
+ return NULL;
+ }
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_probe_resp)
@@ -2439,6 +2464,10 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg)
p2p->go_timeout = 100;
p2p->client_timeout = 20;
+ p2p_dbg(p2p, "initialized");
+ p2p_channels_dump(p2p, "channels", &p2p->cfg->channels);
+ p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels);
+
return p2p;
}
@@ -2475,6 +2504,7 @@ void p2p_deinit(struct p2p_data *p2p)
wpabuf_free(p2p->sd_resp);
os_free(p2p->after_scan_tx);
p2p_remove_wps_vendor_extensions(p2p);
+ os_free(p2p->no_go_freq.range);
os_free(p2p);
}
@@ -4047,6 +4077,31 @@ int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
}
+int p2p_set_no_go_freq(struct p2p_data *p2p,
+ const struct wpa_freq_range_list *list)
+{
+ struct wpa_freq_range *tmp;
+
+ if (list == NULL || list->num == 0) {
+ os_free(p2p->no_go_freq.range);
+ p2p->no_go_freq.range = NULL;
+ p2p->no_go_freq.num = 0;
+ return 0;
+ }
+
+ tmp = os_calloc(list->num, sizeof(struct wpa_freq_range));
+ if (tmp == NULL)
+ return -1;
+ os_memcpy(tmp, list->range, list->num * sizeof(struct wpa_freq_range));
+ os_free(p2p->no_go_freq.range);
+ p2p->no_go_freq.range = tmp;
+ p2p->no_go_freq.num = list->num;
+ p2p_dbg(p2p, "Updated no GO chan list");
+
+ return 0;
+}
+
+
int p2p_get_interface_addr(struct p2p_data *p2p, const u8 *dev_addr,
u8 *iface_addr)
{
@@ -4109,10 +4164,16 @@ void p2p_set_intra_bss_dist(struct p2p_data *p2p, int enabled)
}
-void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan)
+void p2p_update_channel_list(struct p2p_data *p2p,
+ const struct p2p_channels *chan,
+ const struct p2p_channels *cli_chan)
{
p2p_dbg(p2p, "Update channel list");
os_memcpy(&p2p->cfg->channels, chan, sizeof(struct p2p_channels));
+ p2p_channels_dump(p2p, "channels", &p2p->cfg->channels);
+ os_memcpy(&p2p->cfg->cli_channels, cli_chan,
+ sizeof(struct p2p_channels));
+ p2p_channels_dump(p2p, "cli_channels", &p2p->cfg->cli_channels);
}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 7f845b23..cb3991bf 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -77,6 +77,8 @@ struct p2p_go_neg_results {
int ht40;
+ int vht;
+
/**
* ssid - SSID of the group
*/
@@ -287,6 +289,20 @@ struct p2p_config {
struct p2p_channels channels;
/**
+ * cli_channels - Additional client channels
+ *
+ * This list of channels (if any) will be used when advertising local
+ * channels during GO Negotiation or Invitation for the cases where the
+ * local end may become the client. This may allow the peer to become a
+ * GO on additional channels if it supports these options. The main use
+ * case for this is to include passive-scan channels on devices that may
+ * not know their current location and have configured most channels to
+ * not allow initiation of radition (i.e., another device needs to take
+ * master responsibilities).
+ */
+ struct p2p_channels cli_channels;
+
+ /**
* num_pref_chan - Number of pref_chan entries
*/
unsigned int num_pref_chan;
@@ -1649,6 +1665,22 @@ int p2p_channels_includes_freq(const struct p2p_channels *channels,
int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq);
/**
+ * p2p_supported_freq_go - Check whether channel is supported for P2P GO operation
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Channel frequency in MHz
+ * Returns: 0 if channel not usable for P2P, 1 if usable for P2P
+ */
+int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq);
+
+/**
+ * p2p_supported_freq_cli - Check whether channel is supported for P2P client operation
+ * @p2p: P2P module context from p2p_init()
+ * @freq: Channel frequency in MHz
+ * Returns: 0 if channel not usable for P2P, 1 if usable for P2P
+ */
+int p2p_supported_freq_cli(struct p2p_data *p2p, unsigned int freq);
+
+/**
* p2p_get_pref_freq - Get channel from preferred channel list
* @p2p: P2P module context from p2p_init()
* @channels: List of channels
@@ -1657,7 +1689,9 @@ int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq);
unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
const struct p2p_channels *channels);
-void p2p_update_channel_list(struct p2p_data *p2p, struct p2p_channels *chan);
+void p2p_update_channel_list(struct p2p_data *p2p,
+ const struct p2p_channels *chan,
+ const struct p2p_channels *cli_chan);
/**
* p2p_set_best_channels - Update best channel information
@@ -1765,6 +1799,15 @@ int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
const struct p2p_channel *pref_chan);
/**
+ * p2p_set_no_go_freq - Set no GO channel ranges
+ * @p2p: P2P module context from p2p_init()
+ * @list: Channel ranges or %NULL to remove restriction
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_set_no_go_freq(struct p2p_data *p2p,
+ const struct wpa_freq_range_list *list);
+
+/**
* p2p_in_progress - Check whether a P2P operation is progress
* @p2p: P2P module context from p2p_init()
* Returns: 0 if P2P module is idle or 1 if an operation is in progress
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index 5838d35e..3c819ff4 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -327,13 +327,15 @@ void p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p)
}
-static void p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
- const char *val)
+static int p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
+ const char *val)
{
size_t len;
- wpabuf_put_be16(buf, attr);
len = val ? os_strlen(val) : 0;
+ if (wpabuf_tailroom(buf) < 4 + len)
+ return -1;
+ wpabuf_put_be16(buf, attr);
#ifndef CONFIG_WPS_STRICT
if (len == 0) {
/*
@@ -341,36 +343,46 @@ static void p2p_add_wps_string(struct wpabuf *buf, enum wps_attribute attr,
* attributes. As a workaround, send a space character if the
* device attribute string is empty.
*/
+ if (wpabuf_tailroom(buf) < 3)
+ return -1;
wpabuf_put_be16(buf, 1);
wpabuf_put_u8(buf, ' ');
- return;
+ return 0;
}
#endif /* CONFIG_WPS_STRICT */
wpabuf_put_be16(buf, len);
if (val)
wpabuf_put_data(buf, val, len);
+ return 0;
}
-void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
- int all_attr)
+int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
+ int all_attr)
{
u8 *len;
int i;
+ if (wpabuf_tailroom(buf) < 6)
+ return -1;
wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
len = wpabuf_put(buf, 1);
wpabuf_put_be32(buf, WPS_DEV_OUI_WFA);
- wps_build_version(buf);
+ if (wps_build_version(buf) < 0)
+ return -1;
if (all_attr) {
+ if (wpabuf_tailroom(buf) < 5)
+ return -1;
wpabuf_put_be16(buf, ATTR_WPS_STATE);
wpabuf_put_be16(buf, 1);
wpabuf_put_u8(buf, WPS_STATE_NOT_CONFIGURED);
}
if (pw_id >= 0) {
+ if (wpabuf_tailroom(buf) < 6)
+ return -1;
/* Device Password ID */
wpabuf_put_be16(buf, ATTR_DEV_PASSWORD_ID);
wpabuf_put_be16(buf, 2);
@@ -380,33 +392,47 @@ void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
}
if (all_attr) {
+ if (wpabuf_tailroom(buf) < 5)
+ return -1;
wpabuf_put_be16(buf, ATTR_RESPONSE_TYPE);
wpabuf_put_be16(buf, 1);
wpabuf_put_u8(buf, WPS_RESP_ENROLLEE_INFO);
- wps_build_uuid_e(buf, p2p->cfg->uuid);
- p2p_add_wps_string(buf, ATTR_MANUFACTURER,
- p2p->cfg->manufacturer);
- p2p_add_wps_string(buf, ATTR_MODEL_NAME, p2p->cfg->model_name);
- p2p_add_wps_string(buf, ATTR_MODEL_NUMBER,
- p2p->cfg->model_number);
- p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER,
- p2p->cfg->serial_number);
-
+ if (wps_build_uuid_e(buf, p2p->cfg->uuid) < 0 ||
+ p2p_add_wps_string(buf, ATTR_MANUFACTURER,
+ p2p->cfg->manufacturer) < 0 ||
+ p2p_add_wps_string(buf, ATTR_MODEL_NAME,
+ p2p->cfg->model_name) < 0 ||
+ p2p_add_wps_string(buf, ATTR_MODEL_NUMBER,
+ p2p->cfg->model_number) < 0 ||
+ p2p_add_wps_string(buf, ATTR_SERIAL_NUMBER,
+ p2p->cfg->serial_number) < 0)
+ return -1;
+
+ if (wpabuf_tailroom(buf) < 4 + WPS_DEV_TYPE_LEN)
+ return -1;
wpabuf_put_be16(buf, ATTR_PRIMARY_DEV_TYPE);
wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN);
wpabuf_put_data(buf, p2p->cfg->pri_dev_type, WPS_DEV_TYPE_LEN);
- p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name);
+ if (p2p_add_wps_string(buf, ATTR_DEV_NAME, p2p->cfg->dev_name)
+ < 0)
+ return -1;
+ if (wpabuf_tailroom(buf) < 6)
+ return -1;
wpabuf_put_be16(buf, ATTR_CONFIG_METHODS);
wpabuf_put_be16(buf, 2);
wpabuf_put_be16(buf, p2p->cfg->config_methods);
}
- wps_build_wfa_ext(buf, 0, NULL, 0);
+ if (wps_build_wfa_ext(buf, 0, NULL, 0) < 0)
+ return -1;
if (all_attr && p2p->cfg->num_sec_dev_types) {
+ if (wpabuf_tailroom(buf) <
+ 4 + WPS_DEV_TYPE_LEN * p2p->cfg->num_sec_dev_types)
+ return -1;
wpabuf_put_be16(buf, ATTR_SECONDARY_DEV_TYPE_LIST);
wpabuf_put_be16(buf, WPS_DEV_TYPE_LEN *
p2p->cfg->num_sec_dev_types);
@@ -428,4 +454,6 @@ void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
}
p2p_buf_update_ie_hdr(buf, len);
+
+ return 0;
}
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index eea946fa..5faab07c 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -172,7 +172,12 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p,
p2p_buf_update_ie_hdr(buf, len);
/* WPS IE with Device Password ID attribute */
- p2p_build_wps_ie(p2p, buf, p2p_wps_method_pw_id(peer->wps_method), 0);
+ if (p2p_build_wps_ie(p2p, buf, p2p_wps_method_pw_id(peer->wps_method),
+ 0) < 0) {
+ p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Request");
+ wpabuf_free(buf);
+ return NULL;
+ }
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
@@ -307,9 +312,13 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p,
p2p_buf_update_ie_hdr(buf, len);
/* WPS IE with Device Password ID attribute */
- p2p_build_wps_ie(p2p, buf,
- p2p_wps_method_pw_id(peer ? peer->wps_method :
- WPS_NOT_READY), 0);
+ if (p2p_build_wps_ie(p2p, buf,
+ p2p_wps_method_pw_id(peer ? peer->wps_method :
+ WPS_NOT_READY), 0) < 0) {
+ p2p_dbg(p2p, "Failed to build WPS IE for GO Negotiation Response");
+ wpabuf_free(buf);
+ return NULL;
+ }
#ifdef CONFIG_WIFI_DISPLAY
if (p2p->wfd_ie_go_neg)
@@ -403,6 +412,18 @@ void p2p_reselect_channel(struct p2p_data *p2p,
}
}
+ /* Try a channel where we might be able to use VHT */
+ for (i = 0; i < intersection->reg_classes; i++) {
+ struct p2p_reg_class *c = &intersection->reg_class[i];
+ if (c->reg_class == 128) {
+ p2p_dbg(p2p, "Pick possible VHT channel (reg_class %u channel %u) from intersection",
+ c->reg_class, c->channel[0]);
+ p2p->op_reg_class = c->reg_class;
+ p2p->op_channel = c->channel[0];
+ return;
+ }
+ }
+
/* Try a channel where we might be able to use HT40 */
for (i = 0; i < intersection->reg_classes; i++) {
struct p2p_reg_class *c = &intersection->reg_class[i];
@@ -470,12 +491,17 @@ void p2p_reselect_channel(struct p2p_data *p2p,
static int p2p_go_select_channel(struct p2p_data *p2p, struct p2p_device *dev,
u8 *status)
{
- struct p2p_channels intersection;
+ struct p2p_channels tmp, intersection;
p2p_channels_dump(p2p, "own channels", &p2p->channels);
p2p_channels_dump(p2p, "peer channels", &dev->channels);
- p2p_channels_intersect(&p2p->channels, &dev->channels, &intersection);
- p2p_channels_dump(p2p, "intersection", &intersection);
+ p2p_channels_intersect(&p2p->channels, &dev->channels, &tmp);
+ p2p_channels_dump(p2p, "intersection", &tmp);
+ p2p_channels_remove_freqs(&tmp, &p2p->no_go_freq);
+ p2p_channels_dump(p2p, "intersection after no-GO removal", &tmp);
+ p2p_channels_intersect(&tmp, &p2p->cfg->channels, &intersection);
+ p2p_channels_dump(p2p, "intersection with local channel list",
+ &intersection);
if (intersection.reg_classes == 0 ||
intersection.reg_class[0].channels == 0) {
*status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index f9b1e686..276dfd07 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -324,6 +324,8 @@ struct p2p_data {
*/
struct p2p_channels channels;
+ struct wpa_freq_range_list no_go_freq;
+
enum p2p_pending_action_state {
P2P_NO_PENDING_ACTION,
P2P_PENDING_GO_NEG_REQUEST,
@@ -578,6 +580,11 @@ int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel);
void p2p_channels_intersect(const struct p2p_channels *a,
const struct p2p_channels *b,
struct p2p_channels *res);
+void p2p_channels_union(const struct p2p_channels *a,
+ const struct p2p_channels *b,
+ struct p2p_channels *res);
+void p2p_channels_remove_freqs(struct p2p_channels *chan,
+ const struct wpa_freq_range_list *list);
int p2p_channels_includes(const struct p2p_channels *channels, u8 reg_class,
u8 channel);
void p2p_channels_dump(struct p2p_data *p2p, const char *title,
@@ -644,8 +651,8 @@ void p2p_buf_add_noa(struct wpabuf *buf, u8 noa_index, u8 opp_ps, u8 ctwindow,
void p2p_buf_add_ext_listen_timing(struct wpabuf *buf, u16 period,
u16 interval);
void p2p_buf_add_p2p_interface(struct wpabuf *buf, struct p2p_data *p2p);
-void p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
- int all_attr);
+int p2p_build_wps_ie(struct p2p_data *p2p, struct wpabuf *buf, int pw_id,
+ int all_attr);
/* p2p_sd.c */
struct p2p_sd_query * p2p_pending_sd_req(struct p2p_data *p2p,
@@ -737,7 +744,8 @@ int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
size_t len, unsigned int wait_time);
void p2p_stop_listen_for_freq(struct p2p_data *p2p, int freq);
int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
- unsigned int force_freq, unsigned int pref_freq);
+ unsigned int force_freq, unsigned int pref_freq,
+ int go);
void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
PRINTF_FORMAT(2, 3);
void p2p_info(struct p2p_data *p2p, const char *fmt, ...)
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 4e4593e0..203445ba 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -548,7 +548,8 @@ int p2p_invite(struct p2p_data *p2p, const u8 *peer, enum p2p_invite_role role,
return -1;
}
- if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq) < 0)
+ if (p2p_prepare_channel(p2p, dev, force_freq, pref_freq,
+ role != P2P_INVITE_ROLE_CLIENT) < 0)
return -1;
if (persistent_group && role == P2P_INVITE_ROLE_CLIENT && !force_freq &&
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index 8c2d2de2..06ebc606 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -94,6 +94,10 @@ int p2p_channel_to_freq(int op_class, int channel)
if (channel < 149 || channel > 161)
return -1;
return 5000 + 5 * channel;
+ case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
+ if (channel < 36 || channel > 161)
+ return -1;
+ return 5000 + 5 * channel;
}
return -1;
}
@@ -204,6 +208,105 @@ void p2p_channels_intersect(const struct p2p_channels *a,
}
+static void p2p_op_class_union(struct p2p_reg_class *cl,
+ const struct p2p_reg_class *b_cl)
+{
+ size_t i, j;
+
+ for (i = 0; i < b_cl->channels; i++) {
+ for (j = 0; j < cl->channels; j++) {
+ if (b_cl->channel[i] == cl->channel[j])
+ break;
+ }
+ if (j == cl->channels) {
+ if (cl->channels == P2P_MAX_REG_CLASS_CHANNELS)
+ return;
+ cl->channel[cl->channels++] = b_cl->channel[i];
+ }
+ }
+}
+
+
+/**
+ * p2p_channels_union - Union of channel lists
+ * @a: First set of channels
+ * @b: Second set of channels
+ * @res: Data structure for returning the union of channels
+ */
+void p2p_channels_union(const struct p2p_channels *a,
+ const struct p2p_channels *b,
+ struct p2p_channels *res)
+{
+ size_t i, j;
+
+ if (a != res)
+ os_memcpy(res, a, sizeof(*res));
+
+ for (i = 0; i < res->reg_classes; i++) {
+ struct p2p_reg_class *cl = &res->reg_class[i];
+ for (j = 0; j < b->reg_classes; j++) {
+ const struct p2p_reg_class *b_cl = &b->reg_class[j];
+ if (cl->reg_class != b_cl->reg_class)
+ continue;
+ p2p_op_class_union(cl, b_cl);
+ }
+ }
+
+ for (j = 0; j < b->reg_classes; j++) {
+ const struct p2p_reg_class *b_cl = &b->reg_class[j];
+
+ for (i = 0; i < res->reg_classes; i++) {
+ struct p2p_reg_class *cl = &res->reg_class[i];
+ if (cl->reg_class == b_cl->reg_class)
+ break;
+ }
+
+ if (i == res->reg_classes) {
+ if (res->reg_classes == P2P_MAX_REG_CLASSES)
+ return;
+ os_memcpy(&res->reg_class[res->reg_classes++],
+ b_cl, sizeof(struct p2p_reg_class));
+ }
+ }
+}
+
+
+void p2p_channels_remove_freqs(struct p2p_channels *chan,
+ const struct wpa_freq_range_list *list)
+{
+ size_t o, c;
+
+ if (list == NULL)
+ return;
+
+ o = 0;
+ while (o < chan->reg_classes) {
+ struct p2p_reg_class *op = &chan->reg_class[o];
+
+ c = 0;
+ while (c < op->channels) {
+ int freq = p2p_channel_to_freq(op->reg_class,
+ op->channel[c]);
+ if (freq > 0 && freq_range_list_includes(list, freq)) {
+ op->channels--;
+ os_memmove(&op->channel[c],
+ &op->channel[c + 1],
+ op->channels - c);
+ } else
+ c++;
+ }
+
+ if (op->channels == 0) {
+ chan->reg_classes--;
+ os_memmove(&chan->reg_class[o], &chan->reg_class[o + 1],
+ (chan->reg_classes - o) *
+ sizeof(struct p2p_reg_class));
+ } else
+ o++;
+ }
+}
+
+
/**
* p2p_channels_includes - Check whether a channel is included in the list
* @channels: List of supported channels
@@ -284,6 +387,29 @@ int p2p_supported_freq(struct p2p_data *p2p, unsigned int freq)
}
+int p2p_supported_freq_go(struct p2p_data *p2p, unsigned int freq)
+{
+ u8 op_reg_class, op_channel;
+ if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
+ return 0;
+ return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
+ op_channel) &&
+ !freq_range_list_includes(&p2p->no_go_freq, freq);
+}
+
+
+int p2p_supported_freq_cli(struct p2p_data *p2p, unsigned int freq)
+{
+ u8 op_reg_class, op_channel;
+ if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
+ return 0;
+ return p2p_channels_includes(&p2p->cfg->channels, op_reg_class,
+ op_channel) ||
+ p2p_channels_includes(&p2p->cfg->cli_channels, op_reg_class,
+ op_channel);
+}
+
+
unsigned int p2p_get_pref_freq(struct p2p_data *p2p,
const struct p2p_channels *channels)
{
diff --git a/src/radius/radius.c b/src/radius/radius.c
index d1feec96..494f92d1 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -233,7 +233,7 @@ static struct radius_attr_type radius_attrs[] =
{ RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
{ RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 }
};
-#define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))
+#define RADIUS_ATTRS ARRAY_SIZE(radius_attrs)
static struct radius_attr_type *radius_get_attr_type(u8 type)
diff --git a/src/tls/tlsv1_common.c b/src/tls/tlsv1_common.c
index d2128628..4578b227 100644
--- a/src/tls/tlsv1_common.c
+++ b/src/tls/tlsv1_common.c
@@ -57,8 +57,7 @@ static const struct tls_cipher_suite tls_cipher_suites[] = {
TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 }
};
-#define NUM_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
-#define NUM_TLS_CIPHER_SUITES NUM_ELEMS(tls_cipher_suites)
+#define NUM_TLS_CIPHER_SUITES ARRAY_SIZE(tls_cipher_suites)
static const struct tls_cipher_data tls_ciphers[] = {
@@ -84,7 +83,7 @@ static const struct tls_cipher_data tls_ciphers[] = {
CRYPTO_CIPHER_ALG_AES }
};
-#define NUM_TLS_CIPHER_DATA NUM_ELEMS(tls_ciphers)
+#define NUM_TLS_CIPHER_DATA ARRAY_SIZE(tls_ciphers)
/**
diff --git a/src/utils/common.c b/src/utils/common.c
index 5734de71..257bb6d4 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -578,6 +578,21 @@ int is_hex(const u8 *data, size_t len)
}
+int find_first_bit(u32 value)
+{
+ int pos = 0;
+
+ while (value) {
+ if (value & 0x1)
+ return pos;
+ value >>= 1;
+ pos++;
+ }
+
+ return -1;
+}
+
+
size_t merge_byte_arrays(u8 *res, size_t res_len,
const u8 *src1, size_t src1_len,
const u8 *src2, size_t src2_len)
diff --git a/src/utils/common.h b/src/utils/common.h
index 399ab796..028a5eff 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -485,6 +485,7 @@ const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len);
char * wpa_config_parse_string(const char *value, size_t *len);
int is_hex(const u8 *data, size_t len);
+int find_first_bit(u32 value);
size_t merge_byte_arrays(u8 *res, size_t res_len,
const u8 *src1, size_t src1_len,
const u8 *src2, size_t src2_len);
@@ -518,6 +519,8 @@ int freq_range_list_includes(const struct wpa_freq_range_list *list,
unsigned int freq);
char * freq_range_list_str(const struct wpa_freq_range_list *list);
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
/*
* gcc 4.4 ends up generating strict-aliasing warnings about some very common
diff --git a/src/utils/os.h b/src/utils/os.h
index ad208341..2aab13af 100644
--- a/src/utils/os.h
+++ b/src/utils/os.h
@@ -361,15 +361,6 @@ int os_strcmp(const char *s1, const char *s2);
int os_strncmp(const char *s1, const char *s2, size_t n);
/**
- * os_strncpy - Copy a string
- * @dest: Destination
- * @src: Source
- * @n: Maximum number of characters to copy
- * Returns: dest
- */
-char * os_strncpy(char *dest, const char *src, size_t n);
-
-/**
* os_strstr - Locate a substring
* @haystack: String (haystack) to search from
* @needle: Needle to search from haystack
@@ -465,9 +456,6 @@ char * os_strdup(const char *s);
#ifndef os_strncmp
#define os_strncmp(s1, s2, n) strncmp((s1), (s2), (n))
#endif
-#ifndef os_strncpy
-#define os_strncpy(d, s, n) strncpy((d), (s), (n))
-#endif
#ifndef os_strrchr
#define os_strrchr(s, c) strrchr((s), (c))
#endif
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 10b9e0da..960073a5 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -17,10 +17,10 @@
#endif /* ANDROID */
#include "os.h"
+#include "common.h"
#ifdef WPA_TRACE
-#include "common.h"
#include "wpa_debug.h"
#include "trace.h"
#include "list.h"
@@ -268,7 +268,7 @@ int os_program_init(void)
struct __user_cap_header_struct header;
struct __user_cap_data_struct cap;
- setgroups(sizeof(groups)/sizeof(groups[0]), groups);
+ setgroups(ARRAY_SIZE(groups), groups);
prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c
index ac9bb1e2..3be89453 100644
--- a/src/wps/wps_attr_build.c
+++ b/src/wps/wps_attr_build.c
@@ -118,6 +118,8 @@ int wps_build_config_methods(struct wpabuf *msg, u16 methods)
int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid)
{
+ if (wpabuf_tailroom(msg) < 4 + WPS_UUID_LEN)
+ return -1;
wpa_printf(MSG_DEBUG, "WPS: * UUID-E");
wpabuf_put_be16(msg, ATTR_UUID_E);
wpabuf_put_be16(msg, WPS_UUID_LEN);
@@ -183,6 +185,8 @@ int wps_build_version(struct wpabuf *msg)
* backwards compatibility reasons. The real version negotiation is
* done with Version2.
*/
+ if (wpabuf_tailroom(msg) < 5)
+ return -1;
wpa_printf(MSG_DEBUG, "WPS: * Version (hardcoded 0x10)");
wpabuf_put_be16(msg, ATTR_VERSION);
wpabuf_put_be16(msg, 1);
@@ -197,6 +201,10 @@ int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
#ifdef CONFIG_WPS2
u8 *len;
+ if (wpabuf_tailroom(msg) <
+ 7 + 3 + (req_to_enroll ? 3 : 0) +
+ (auth_macs ? 2 + auth_macs_count * ETH_ALEN : 0))
+ return -1;
wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
len = wpabuf_put(msg, 2); /* to be filled */
wpabuf_put_be24(msg, WPS_VENDOR_ID_WFA);
@@ -230,6 +238,8 @@ int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
#ifdef CONFIG_WPS_TESTING
if (WPS_VERSION > 0x20) {
+ if (wpabuf_tailroom(msg) < 5)
+ return -1;
wpa_printf(MSG_DEBUG, "WPS: * Extensibility Testing - extra "
"attribute");
wpabuf_put_be16(msg, ATTR_EXTENSIBILITY_TEST);
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 50759769..a6c795fc 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -772,6 +772,9 @@ OBJS += src/ap/beacon.c
OBJS += src/ap/eap_user_db.c
ifdef CONFIG_IEEE80211N
OBJS += src/ap/ieee802_11_ht.c
+ifdef CONFIG_IEEE80211AC
+OBJS += src/ap/ieee802_11_vht.c
+endif
endif
ifdef CONFIG_WNM
OBJS += src/ap/wnm_ap.c
@@ -787,6 +790,9 @@ OBJS += src/eap_server/eap_server_methods.c
ifdef CONFIG_IEEE80211N
L_CFLAGS += -DCONFIG_IEEE80211N
+ifdef CONFIG_IEEE80211AC
+L_CFLAGS += -DCONFIG_IEEE80211AC
+endif
endif
ifdef NEED_AP_MLME
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 7c442413..8dcb71b1 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -750,6 +750,9 @@ OBJS += ../src/ap/beacon.o
OBJS += ../src/ap/eap_user_db.o
ifdef CONFIG_IEEE80211N
OBJS += ../src/ap/ieee802_11_ht.o
+ifdef CONFIG_IEEE80211AC
+OBJS += ../src/ap/ieee802_11_vht.o
+endif
endif
ifdef CONFIG_WNM
OBJS += ../src/ap/wnm_ap.o
@@ -765,6 +768,9 @@ OBJS += ../src/eap_server/eap_server_methods.o
ifdef CONFIG_IEEE80211N
CFLAGS += -DCONFIG_IEEE80211N
+ifdef CONFIG_IEEE80211AC
+CFLAGS += -DCONFIG_IEEE80211AC
+endif
endif
ifdef NEED_AP_MLME
diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P
index 76f82191..ffc2baf0 100644
--- a/wpa_supplicant/README-P2P
+++ b/wpa_supplicant/README-P2P
@@ -125,7 +125,7 @@ join-a-group style PD instead of GO Negotiation style PD.
p2p_connect <peer device address> <pbc|pin|PIN#> [display|keypad]
[persistent|persistent=<network id>] [join|auth]
- [go_intent=<0..15>] [freq=<in MHz>] [ht40] [provdisc]
+ [go_intent=<0..15>] [freq=<in MHz>] [ht40] [vht] [provdisc]
Start P2P group formation with a discovered P2P peer. This includes
optional group owner negotiation, group interface setup, provisioning,
@@ -166,7 +166,8 @@ used prior to starting GO Negotiation as a workaround with some deployed
P2P implementations that require this to allow the user to accept the
connection.
-p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>] [ht40]
+p2p_group_add [persistent|persistent=<network id>] [freq=<freq in MHz>]
+ [ht40] [vht]
Set up a P2P group owner manually (i.e., without group owner
negotiation with a specific peer). This is also known as autonomous
@@ -373,7 +374,8 @@ Remove all local services from internal SD query processing.
Invitation
p2p_invite [persistent=<network id>|group=<group ifname>] [peer=address]
- [go_dev_addr=address] [freq=<freq in MHz>] [ht40] [pref=<MHz>]
+ [go_dev_addr=address] [freq=<freq in MHz>] [ht40] [vht]
+ [pref=<MHz>]
Invite a peer to join a group (e.g., group=wlan1) or to reinvoke a
persistent group (e.g., persistent=4). If the peer device is the GO of
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index fdbe248a..b7b58cdb 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -42,6 +42,33 @@ static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
#endif /* CONFIG_WPS */
+#ifdef CONFIG_IEEE80211N
+static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
+ struct hostapd_config *conf,
+ struct hostapd_hw_modes *mode)
+{
+ u8 center_chan = 0;
+ u8 channel = conf->channel;
+
+ if (!conf->secondary_channel)
+ goto no_vht;
+
+ center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel);
+ if (!center_chan)
+ goto no_vht;
+
+ /* Use 80 MHz channel */
+ conf->vht_oper_chwidth = 1;
+ conf->vht_oper_centr_freq_seg0_idx = center_chan;
+ return;
+
+no_vht:
+ conf->vht_oper_centr_freq_seg0_idx =
+ channel + conf->secondary_channel * 2;
+}
+#endif /* CONFIG_IEEE80211N */
+
+
static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
struct hostapd_config *conf)
@@ -114,6 +141,11 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
HT_CAP_INFO_SHORT_GI40MHZ |
HT_CAP_INFO_RX_STBC_MASK |
HT_CAP_INFO_MAX_AMSDU_SIZE);
+
+ if (mode->vht_capab && ssid->vht) {
+ conf->ieee80211ac = 1;
+ wpas_conf_ap_vht(wpa_s, conf, mode);
+ }
}
}
#endif /* CONFIG_IEEE80211N */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index ea7ac5af..08d2ecdd 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1686,7 +1686,7 @@ static const struct parse_data ssid_fields[] = {
#undef _FUNC
#undef FUNC
#undef FUNC_KEY
-#define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0]))
+#define NUM_SSID_FIELDS ARRAY_SIZE(ssid_fields)
/**
@@ -1936,6 +1936,7 @@ void wpa_config_free(struct wpa_config *config)
os_free(config->p2p_ssid_postfix);
os_free(config->pssid);
os_free(config->p2p_pref_chan);
+ os_free(config->p2p_no_go_freq.range);
os_free(config->autoscan);
os_free(config->freq_list);
wpabuf_free(config->wps_nfc_dh_pubkey);
@@ -3079,6 +3080,26 @@ fail:
wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_pref_chan list", line);
return -1;
}
+
+
+static int wpa_config_process_p2p_no_go_freq(
+ const struct global_parse_data *data,
+ struct wpa_config *config, int line, const char *pos)
+{
+ int ret;
+
+ ret = freq_range_list_parse(&config->p2p_no_go_freq, pos);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_no_go_freq", line);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "P2P: p2p_no_go_freq with %u items",
+ config->p2p_no_go_freq.num);
+
+ return 0;
+}
+
#endif /* CONFIG_P2P */
@@ -3229,7 +3250,10 @@ static const struct global_parse_data global_fields[] = {
{ INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
{ INT(p2p_group_idle), 0 },
{ FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
+ { FUNC(p2p_no_go_freq), CFG_CHANGED_P2P_PREF_CHAN },
+ { INT_RANGE(p2p_add_cli_chan, 0, 1), 0 },
{ INT(p2p_go_ht40), 0 },
+ { INT(p2p_go_vht), 0 },
{ INT(p2p_disabled), 0 },
{ INT(p2p_no_group_iface), 0 },
{ INT_RANGE(p2p_ignore_shared_freq, 0, 1), 0 },
@@ -3278,7 +3302,7 @@ static const struct global_parse_data global_fields[] = {
#undef STR
#undef STR_RANGE
#undef BIN
-#define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))
+#define NUM_GLOBAL_FIELDS ARRAY_SIZE(global_fields)
int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 2e558fdb..8cbeb628 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -605,6 +605,8 @@ struct wpa_config {
int p2p_intra_bss;
unsigned int num_p2p_pref_chan;
struct p2p_channel *p2p_pref_chan;
+ struct wpa_freq_range_list p2p_no_go_freq;
+ int p2p_add_cli_chan;
int p2p_ignore_shared_freq;
struct wpabuf *wps_vendor_ext_m1;
@@ -826,6 +828,16 @@ struct wpa_config {
int p2p_go_ht40;
/**
+ * p2p_go_vht - Default mode for VHT enable when operating as GO
+ *
+ * This will take effect for p2p_group_add, p2p_connect, and p2p_invite.
+ * Note that regulatory constraints and driver capabilities are
+ * consulted anyway, so setting it to 1 can't do real harm.
+ * By default: 0 (disabled)
+ */
+ int p2p_go_vht;
+
+ /**
* p2p_disabled - Whether P2P operations are disabled for this interface
*/
int p2p_disabled;
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index b8fff70c..cb2dde8e 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -941,8 +941,19 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
}
fprintf(f, "\n");
}
+ if (config->p2p_no_go_freq.num) {
+ char *val = freq_range_list_str(&config->p2p_no_go_freq);
+ if (val) {
+ fprintf(f, "p2p_no_go_freq=%s\n", val);
+ os_free(val);
+ }
+ }
+ if (config->p2p_add_cli_chan)
+ fprintf(f, "p2p_add_cli_chan=%d\n", config->p2p_add_cli_chan);
if (config->p2p_go_ht40)
fprintf(f, "p2p_go_ht40=%u\n", config->p2p_go_ht40);
+ if (config->p2p_go_vht)
+ fprintf(f, "p2p_go_vht=%u\n", config->p2p_go_vht);
if (config->p2p_disabled)
fprintf(f, "p2p_disabled=%u\n", config->p2p_disabled);
if (config->p2p_no_group_iface)
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index c6ea9630..3d008ca5 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -394,6 +394,8 @@ struct wpa_ssid {
int ht40;
+ int vht;
+
/**
* wpa_ptk_rekey - Maximum lifetime for PTK in seconds
*
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 0622b650..1b2bbbb6 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -1569,10 +1569,8 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
if (wpa_s->current_ssid->parent_cred != cred)
continue;
- if (!cred->domain)
- continue;
- for (i = 0; i < cred->num_domain; i++) {
+ for (i = 0; cred->domain && i < cred->num_domain; i++) {
ret = os_snprintf(pos, end - pos,
"home_sp=%s\n",
cred->domain[i]);
@@ -3707,12 +3705,12 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
int go_intent = -1;
int freq = 0;
int pd;
- int ht40;
+ int ht40, vht;
/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
* [persistent|persistent=<network id>]
* [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
- * [ht40] */
+ * [ht40] [vht] */
if (hwaddr_aton(cmd, addr))
return -1;
@@ -3740,7 +3738,9 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
auth = os_strstr(pos, " auth") != NULL;
automatic = os_strstr(pos, " auto") != NULL;
pd = os_strstr(pos, " provdisc") != NULL;
- ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+ vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
+ ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
+ vht;
pos2 = os_strstr(pos, " go_intent=");
if (pos2) {
@@ -3781,7 +3781,7 @@ static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, automatic, join,
auth, go_intent, freq, persistent_id, pd,
- ht40);
+ ht40, vht);
if (new_pin == -2) {
os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
return 25;
@@ -4145,7 +4145,7 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
struct wpa_ssid *ssid;
u8 *_peer = NULL, peer[ETH_ALEN];
int freq = 0, pref_freq = 0;
- int ht40;
+ int ht40, vht;
id = atoi(cmd);
pos = os_strstr(cmd, " peer=");
@@ -4179,9 +4179,12 @@ static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
return -1;
}
- ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+ vht = (os_strstr(cmd, " vht") != NULL) || wpa_s->conf->p2p_go_vht;
+ ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
+ vht;
- return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, pref_freq);
+ return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40, vht,
+ pref_freq);
}
@@ -4228,7 +4231,8 @@ static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
- char *cmd, int freq, int ht40)
+ char *cmd, int freq, int ht40,
+ int vht)
{
int id;
struct wpa_ssid *ssid;
@@ -4242,32 +4246,34 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
return -1;
}
- return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40, NULL,
- 0);
+ return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40, vht,
+ NULL, 0);
}
static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
{
- int freq = 0, ht40;
+ int freq = 0, ht40, vht;
char *pos;
pos = os_strstr(cmd, "freq=");
if (pos)
freq = atoi(pos + 5);
- ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+ vht = (os_strstr(cmd, "vht") != NULL) || wpa_s->conf->p2p_go_vht;
+ ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40 ||
+ vht;
if (os_strncmp(cmd, "persistent=", 11) == 0)
return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
- ht40);
+ ht40, vht);
if (os_strcmp(cmd, "persistent") == 0 ||
os_strncmp(cmd, "persistent ", 11) == 0)
- return wpas_p2p_group_add(wpa_s, 1, freq, ht40);
+ return wpas_p2p_group_add(wpa_s, 1, freq, ht40, vht);
if (os_strncmp(cmd, "freq=", 5) == 0)
- return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
+ return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
if (ht40)
- return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
+ return wpas_p2p_group_add(wpa_s, 0, freq, ht40, vht);
wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
cmd);
@@ -5180,6 +5186,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpas_wps_cancel(wpa_s);
#endif /* CONFIG_WPS */
wpa_s->after_wps = 0;
+ wpa_s->known_wps_freq = 0;
#ifdef CONFIG_TDLS_TESTING
extern unsigned int tdls_testing;
@@ -5453,7 +5460,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
if (wpas_p2p_group_remove(wpa_s, buf + 17))
reply_len = -1;
} else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
- if (wpas_p2p_group_add(wpa_s, 0, 0, 0))
+ if (wpas_p2p_group_add(wpa_s, 0, 0, 0, 0))
reply_len = -1;
} else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
if (p2p_ctrl_group_add(wpa_s, buf + 14))
@@ -5614,6 +5621,7 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
wpa_s->normal_scans = 0;
wpa_s->scan_req = MANUAL_SCAN_REQ;
wpa_s->after_wps = 0;
+ wpa_s->known_wps_freq = 0;
wpa_supplicant_req_scan(wpa_s, 0, 0);
} else if (wpa_s->sched_scanning) {
wpa_printf(MSG_DEBUG, "Stop ongoing "
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 5fe9a4e4..7135d068 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -724,6 +724,7 @@ static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
if (sock < 0) {
wpa_dbg(wpa_s, MSG_DEBUG,
"Failed to reinitialize ctrl_iface socket");
+ break;
}
}
}
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index bb6b7b98..9f923e6b 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -2030,7 +2030,7 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
const char *args[] = {"ccmp", "tkip", "none"};
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Pairwise", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto nomem;
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
@@ -2077,7 +2077,7 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
};
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Group", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto nomem;
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
@@ -2134,7 +2134,7 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
};
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "KeyMgmt", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto nomem;
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
@@ -2214,7 +2214,7 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
const char *args[] = { "rsn", "wpa" };
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "Protocol", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto nomem;
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
@@ -2249,7 +2249,7 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
const char *args[] = { "open", "shared", "leap" };
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "AuthAlg", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto nomem;
} else {
if (!wpa_dbus_dict_begin_string_array(&iter_dict, "AuthAlg",
@@ -2285,7 +2285,7 @@ dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
/***** Scan */
if (!wpa_dbus_dict_append_string_array(&iter_dict, "Scan", scans,
- sizeof(scans) / sizeof(char *)))
+ ARRAY_SIZE(scans)))
goto nomem;
/***** Modes */
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 52b36b4a..5150a76b 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -346,14 +346,14 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
if (ssid == NULL || ssid->disabled != 2)
goto inv_args;
- if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0,
+ if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0,
NULL, 0)) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
goto out;
}
- } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0))
+ } else if (wpas_p2p_group_add(wpa_s, persistent_group, freq, 0, 0))
goto inv_args;
out:
@@ -505,7 +505,7 @@ DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
persistent_group, 0, join, authorize_only,
- go_intent, freq, -1, 0, 0);
+ go_intent, freq, -1, 0, 0, 0);
if (new_pin >= 0) {
char npin[9];
@@ -631,8 +631,8 @@ DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
if (ssid == NULL || ssid->disabled != 2)
goto err;
- if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0) < 0)
- {
+ if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL, 0, 0, 0, 0) <
+ 0) {
reply = wpas_dbus_error_unknown_error(
message,
"Failed to reinvoke a persistent group");
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c
index e565de93..6d178f45 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers.c
@@ -539,7 +539,7 @@ DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
const char *args[] = {"CCMP", "TKIP", "NONE"};
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "pairwise", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto error;
}
} else {
@@ -582,7 +582,7 @@ DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
};
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "group", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto error;
}
} else {
@@ -632,7 +632,7 @@ DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
};
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "key_mgmt", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto error;
}
} else {
@@ -683,7 +683,7 @@ DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
const char *args[] = { "RSN", "WPA" };
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "proto", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto error;
}
} else {
@@ -720,7 +720,7 @@ DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
const char *args[] = { "OPEN", "SHARED", "LEAP" };
if (!wpa_dbus_dict_append_string_array(
&iter_dict, "auth_alg", args,
- sizeof(args) / sizeof(char*)))
+ ARRAY_SIZE(args)))
goto error;
}
} else {
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index aa6005f7..98fa30f4 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -484,6 +484,10 @@ CONFIG_PEERKEY=y
# IEEE 802.11n (High Throughput) support (mainly for AP mode)
#CONFIG_IEEE80211N=y
+# IEEE 802.11ac (Very High Throughput) support (mainly for AP mode)
+# (depends on CONFIG_IEEE80211N)
+#CONFIG_IEEE80211AC=y
+
# Wireless Network Management (IEEE Std 802.11v-2011)
# Note: This is experimental and not complete implementation.
#CONFIG_WNM=y
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index e2949179..067b3bd4 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -1550,6 +1550,7 @@ int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
struct wpabuf *domain_names)
{
size_t i;
+ int ret = -1;
#ifdef INTERWORKING_3GPP
char nai[100], *realm;
@@ -1580,11 +1581,13 @@ int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
if (realm &&
domain_name_list_contains(domain_names, realm))
return 1;
+ if (realm)
+ ret = 0;
}
#endif /* INTERWORKING_3GPP */
if (domain_names == NULL || cred->domain == NULL)
- return 0;
+ return ret;
for (i = 0; i < cred->num_domain; i++) {
wpa_printf(MSG_DEBUG, "Interworking: Search for match with "
@@ -2099,7 +2102,10 @@ int interworking_select(struct wpa_supplicant *wpa_s, int auto_select)
wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
"selection");
wpa_s->scan_res_handler = interworking_scan_res_handler;
+ wpa_s->normal_scans = 0;
wpa_s->scan_req = MANUAL_SCAN_REQ;
+ wpa_s->after_wps = 0;
+ wpa_s->known_wps_freq = 0;
wpa_supplicant_req_scan(wpa_s, 0, 0);
return 0;
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 66849d37..c4e42eab 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -1113,6 +1113,7 @@ static void wpas_start_wps_go(struct wpa_supplicant *wpa_s,
WPAS_MODE_P2P_GO;
ssid->frequency = params->freq;
ssid->ht40 = params->ht40;
+ ssid->vht = params->vht;
ssid->ssid = os_zalloc(params->ssid_len + 1);
if (ssid->ssid) {
os_memcpy(ssid->ssid, params->ssid, params->ssid_len);
@@ -1200,8 +1201,7 @@ static void wpas_p2p_get_group_ifname(struct wpa_supplicant *wpa_s,
if (os_strlen(ifname) >= IFNAMSIZ &&
os_strlen(wpa_s->ifname) < IFNAMSIZ) {
/* Try to avoid going over the IFNAMSIZ length limit */
- os_snprintf(ifname, sizeof(ifname), "p2p-%d",
- wpa_s->p2p_group_idx);
+ os_snprintf(ifname, len, "p2p-%d", wpa_s->p2p_group_idx);
}
}
@@ -1373,6 +1373,8 @@ void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res)
if (wpa_s->p2p_go_ht40)
res->ht40 = 1;
+ if (wpa_s->p2p_go_vht)
+ res->vht = 1;
wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS "role=%s "
"freq=%d ht40=%d peer_dev=" MACSTR " peer_iface=" MACSTR
@@ -2763,7 +2765,7 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid,
if (s) {
int go = s->mode == WPAS_MODE_P2P_GO;
wpas_p2p_group_add_persistent(
- wpa_s, s, go, go ? op_freq : 0, 0, NULL,
+ wpa_s, s, go, go ? op_freq : 0, 0, 0, NULL,
go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0);
} else if (bssid) {
wpa_s->user_initiated_pd = 0;
@@ -2939,7 +2941,8 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid,
wpas_p2p_group_add_persistent(wpa_s, ssid,
ssid->mode == WPAS_MODE_P2P_GO,
wpa_s->p2p_persistent_go_freq,
- wpa_s->p2p_go_ht40, channels,
+ wpa_s->p2p_go_ht40, wpa_s->p2p_go_vht,
+ channels,
ssid->mode == WPAS_MODE_P2P_GO ?
P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE :
0);
@@ -2961,10 +2964,13 @@ static void wpas_p2p_add_chan(struct p2p_reg_class *reg, u8 chan)
static int wpas_p2p_default_channels(struct wpa_supplicant *wpa_s,
- struct p2p_channels *chan)
+ struct p2p_channels *chan,
+ struct p2p_channels *cli_chan)
{
int i, cla = 0;
+ os_memset(cli_chan, 0, sizeof(*cli_chan));
+
wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for 2.4 GHz "
"band");
@@ -3032,6 +3038,10 @@ static struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
}
+enum chan_allowed {
+ NOT_ALLOWED, PASSIVE_ONLY, ALLOWED
+};
+
static int has_channel(struct wpa_global *global,
struct hostapd_hw_modes *mode, u8 chan, int *flags)
{
@@ -3041,21 +3051,25 @@ static int has_channel(struct wpa_global *global,
freq = (mode->mode == HOSTAPD_MODE_IEEE80211A ? 5000 : 2407) +
chan * 5;
if (wpas_p2p_disallowed_freq(global, freq))
- return 0;
+ return NOT_ALLOWED;
for (i = 0; i < mode->num_channels; i++) {
if (mode->channels[i].chan == chan) {
if (flags)
*flags = mode->channels[i].flag;
- return !(mode->channels[i].flag &
- (HOSTAPD_CHAN_DISABLED |
- HOSTAPD_CHAN_PASSIVE_SCAN |
- HOSTAPD_CHAN_NO_IBSS |
- HOSTAPD_CHAN_RADAR));
+ if (mode->channels[i].flag &
+ (HOSTAPD_CHAN_DISABLED |
+ HOSTAPD_CHAN_RADAR))
+ return NOT_ALLOWED;
+ if (mode->channels[i].flag &
+ (HOSTAPD_CHAN_PASSIVE_SCAN |
+ HOSTAPD_CHAN_NO_IBSS))
+ return PASSIVE_ONLY;
+ return ALLOWED;
}
}
- return 0;
+ return NOT_ALLOWED;
}
@@ -3065,7 +3079,7 @@ struct p2p_oper_class_map {
u8 min_chan;
u8 max_chan;
u8 inc;
- enum { BW20, BW40PLUS, BW40MINUS } bw;
+ enum { BW20, BW40PLUS, BW40MINUS, BW80 } bw;
};
static struct p2p_oper_class_map op_class[] = {
@@ -3080,73 +3094,171 @@ static struct p2p_oper_class_map op_class[] = {
{ HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
{ HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
{ HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS },
+
+ /*
+ * IEEE P802.11ac/D7.0 Table E-4 actually talks about channel center
+ * frequency index 42, 58, 106, 122, 138, 155 with channel spacing of
+ * 80 MHz, but currently use the following definition for simplicity
+ * (these center frequencies are not actual channels, which makes
+ * has_channel() fail). wpas_p2p_verify_80mhz() should take care of
+ * removing invalid channels.
+ */
+ { HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80 },
{ -1, 0, 0, 0, 0, BW20 }
};
-static int wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
- struct hostapd_hw_modes *mode,
- u8 channel, u8 bw)
+static int wpas_p2p_get_center_80mhz(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode,
+ u8 channel)
{
- int flag;
+ u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
+ unsigned int i;
- if (!has_channel(wpa_s->global, mode, channel, &flag))
- return -1;
- if (bw == BW40MINUS &&
- (!(flag & HOSTAPD_CHAN_HT40MINUS) ||
- !has_channel(wpa_s->global, mode, channel - 4, NULL)))
- return 0;
- if (bw == BW40PLUS &&
- (!(flag & HOSTAPD_CHAN_HT40PLUS) ||
- !has_channel(wpa_s->global, mode, channel + 4, NULL)))
+ if (mode->mode != HOSTAPD_MODE_IEEE80211A)
return 0;
- return 1;
+
+ for (i = 0; i < ARRAY_SIZE(center_channels); i++)
+ /*
+ * In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48),
+ * so the center channel is 6 channels away from the start/end.
+ */
+ if (channel >= center_channels[i] - 6 &&
+ channel <= center_channels[i] + 6)
+ return center_channels[i];
+
+ return 0;
+}
+
+
+static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode,
+ u8 channel, u8 bw)
+{
+ u8 center_chan;
+ int i, flags;
+ enum chan_allowed res, ret = ALLOWED;
+
+ center_chan = wpas_p2p_get_center_80mhz(wpa_s, mode, channel);
+ if (!center_chan)
+ return NOT_ALLOWED;
+ if (center_chan >= 58 && center_chan <= 138)
+ return NOT_ALLOWED; /* Do not allow DFS channels for P2P */
+
+ /* check all the channels are available */
+ for (i = 0; i < 4; i++) {
+ int adj_chan = center_chan - 6 + i * 4;
+
+ res = has_channel(wpa_s->global, mode, adj_chan, &flags);
+ if (res == NOT_ALLOWED)
+ return NOT_ALLOWED;
+ if (res == PASSIVE_ONLY)
+ ret = PASSIVE_ONLY;
+
+ if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70))
+ return NOT_ALLOWED;
+ if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50))
+ return NOT_ALLOWED;
+ if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30))
+ return NOT_ALLOWED;
+ if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_10))
+ return NOT_ALLOWED;
+ }
+
+ return ret;
+}
+
+
+static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode,
+ u8 channel, u8 bw)
+{
+ int flag;
+ enum chan_allowed res, res2;
+
+ res2 = res = has_channel(wpa_s->global, mode, channel, &flag);
+ if (bw == BW40MINUS) {
+ if (!(flag & HOSTAPD_CHAN_HT40MINUS))
+ return NOT_ALLOWED;
+ res2 = has_channel(wpa_s->global, mode, channel - 4, NULL);
+ } else if (bw == BW40PLUS) {
+ if (!(flag & HOSTAPD_CHAN_HT40PLUS))
+ return NOT_ALLOWED;
+ res2 = has_channel(wpa_s->global, mode, channel + 4, NULL);
+ } else if (bw == BW80) {
+ res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw);
+ }
+
+ if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
+ return NOT_ALLOWED;
+ if (res == PASSIVE_ONLY || res2 == PASSIVE_ONLY)
+ return PASSIVE_ONLY;
+ return res;
}
static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
- struct p2p_channels *chan)
+ struct p2p_channels *chan,
+ struct p2p_channels *cli_chan)
{
struct hostapd_hw_modes *mode;
- int cla, op;
+ int cla, op, cli_cla;
if (wpa_s->hw.modes == NULL) {
wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching "
"of all supported channels; assume dualband "
"support");
- return wpas_p2p_default_channels(wpa_s, chan);
+ return wpas_p2p_default_channels(wpa_s, chan, cli_chan);
}
- cla = 0;
+ cla = cli_cla = 0;
for (op = 0; op_class[op].op_class; op++) {
struct p2p_oper_class_map *o = &op_class[op];
u8 ch;
- struct p2p_reg_class *reg = NULL;
+ struct p2p_reg_class *reg = NULL, *cli_reg = NULL;
mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
if (mode == NULL)
continue;
for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
- if (wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw) < 1)
- continue;
- if (reg == NULL) {
- wpa_printf(MSG_DEBUG, "P2P: Add operating "
- "class %u", o->op_class);
- reg = &chan->reg_class[cla];
- cla++;
- reg->reg_class = o->op_class;
+ enum chan_allowed res;
+ res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
+ if (res == ALLOWED) {
+ if (reg == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Add operating class %u",
+ o->op_class);
+ reg = &chan->reg_class[cla];
+ cla++;
+ reg->reg_class = o->op_class;
+ }
+ reg->channel[reg->channels] = ch;
+ reg->channels++;
+ } else if (res == PASSIVE_ONLY &&
+ wpa_s->conf->p2p_add_cli_chan) {
+ if (cli_reg == NULL) {
+ wpa_printf(MSG_DEBUG, "P2P: Add operating class %u (client only)",
+ o->op_class);
+ cli_reg = &cli_chan->reg_class[cli_cla];
+ cli_cla++;
+ cli_reg->reg_class = o->op_class;
+ }
+ cli_reg->channel[cli_reg->channels] = ch;
+ cli_reg->channels++;
}
- reg->channel[reg->channels] = ch;
- reg->channels++;
}
if (reg) {
wpa_hexdump(MSG_DEBUG, "P2P: Channels",
reg->channel, reg->channels);
}
+ if (cli_reg) {
+ wpa_hexdump(MSG_DEBUG, "P2P: Channels (client only)",
+ cli_reg->channel, cli_reg->channels);
+ }
}
chan->reg_classes = cla;
+ cli_chan->reg_classes = cli_cla;
return 0;
}
@@ -3155,7 +3267,8 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode, u8 channel)
{
- int op, ret;
+ int op;
+ enum chan_allowed ret;
for (op = 0; op_class[op].op_class; op++) {
struct p2p_oper_class_map *o = &op_class[op];
@@ -3166,18 +3279,24 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
o->bw == BW20 || ch != channel)
continue;
ret = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
- if (ret < 0)
- continue;
- else if (ret > 0)
+ if (ret == ALLOWED)
return (o->bw == BW40MINUS) ? -1 : 1;
- else
- return 0;
}
}
return 0;
}
+int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode, u8 channel)
+{
+ if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW80))
+ return 0;
+
+ return wpas_p2p_get_center_80mhz(wpa_s, mode, channel);
+}
+
+
static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf,
size_t buf_len)
{
@@ -3385,7 +3504,7 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
} else
os_memcpy(p2p.country, "XX\x04", 3);
- if (wpas_p2p_setup_channels(wpa_s, &p2p.channels)) {
+ if (wpas_p2p_setup_channels(wpa_s, &p2p.channels, &p2p.cli_channels)) {
wpa_printf(MSG_ERROR, "P2P: Failed to configure supported "
"channel list");
return -1;
@@ -3428,6 +3547,8 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s)
global->p2p, wpa_s->conf->wps_vendor_ext[i]);
}
+ p2p_set_no_go_freq(global->p2p, &wpa_s->conf->p2p_no_go_freq);
+
return 0;
}
@@ -3745,7 +3866,8 @@ static void wpas_p2p_scan_res_join(struct wpa_supplicant *wpa_s,
wpa_s->p2p_connect_freq,
wpa_s->p2p_persistent_id,
wpa_s->p2p_pd_before_go_neg,
- wpa_s->p2p_go_ht40);
+ wpa_s->p2p_go_ht40,
+ wpa_s->p2p_go_vht);
return;
}
@@ -4027,7 +4149,7 @@ static int wpas_p2p_join_start(struct wpa_supplicant *wpa_s)
static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
- int *force_freq, int *pref_freq)
+ int *force_freq, int *pref_freq, int go)
{
int *freqs, res;
unsigned int freq_in_use = 0, num, i;
@@ -4043,7 +4165,12 @@ static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq,
freq, wpa_s->num_multichan_concurrent, num);
if (freq > 0) {
- if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+ int ret;
+ if (go)
+ ret = p2p_supported_freq(wpa_s->global->p2p, freq);
+ else
+ ret = p2p_supported_freq_cli(wpa_s->global->p2p, freq);
+ if (!ret) {
wpa_printf(MSG_DEBUG, "P2P: The forced channel "
"(%u MHz) is not supported for P2P uses",
freq);
@@ -4128,6 +4255,7 @@ exit_free:
* @pd: Whether to send Provision Discovery prior to GO Negotiation as an
* interoperability workaround when initiating group formation
* @ht40: Start GO with 40 MHz channel width
+ * @vht: Start GO with VHT support
* Returns: 0 or new PIN (if pin was %NULL) on success, -1 on unspecified
* failure, -2 on failure due to channel not currently available,
* -3 if forced channel is not supported
@@ -4136,7 +4264,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
const char *pin, enum p2p_wps_method wps_method,
int persistent_group, int auto_join, int join, int auth,
int go_intent, int freq, int persistent_id, int pd,
- int ht40)
+ int ht40, int vht)
{
int force_freq = 0, pref_freq = 0;
int ret = 0, res;
@@ -4171,6 +4299,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
wpa_s->p2p_fallback_to_go_neg = 0;
wpa_s->p2p_pd_before_go_neg = !!pd;
wpa_s->p2p_go_ht40 = !!ht40;
+ wpa_s->p2p_go_vht = !!vht;
if (pin)
os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
@@ -4213,7 +4342,8 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
return ret;
}
- res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq);
+ res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+ go_intent == 15);
if (res)
return res;
wpas_p2p_set_own_freq_preference(wpa_s, force_freq);
@@ -4376,8 +4506,8 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq)
wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
"band");
if (wpa_s->best_24_freq > 0 &&
- p2p_supported_freq(wpa_s->global->p2p,
- wpa_s->best_24_freq)) {
+ p2p_supported_freq_go(wpa_s->global->p2p,
+ wpa_s->best_24_freq)) {
freq = wpa_s->best_24_freq;
wpa_printf(MSG_DEBUG, "P2P: Use best 2.4 GHz band "
"channel: %d MHz", freq);
@@ -4393,7 +4523,7 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq)
wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 5 GHz "
"band");
if (wpa_s->best_5_freq > 0 &&
- p2p_supported_freq(wpa_s->global->p2p,
+ p2p_supported_freq_go(wpa_s->global->p2p,
wpa_s->best_5_freq)) {
freq = wpa_s->best_5_freq;
wpa_printf(MSG_DEBUG, "P2P: Use best 5 GHz band "
@@ -4401,7 +4531,7 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq)
} else {
os_get_random((u8 *) &r, sizeof(r));
freq = 5180 + (r % 4) * 20;
- if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
+ if (!p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
wpa_printf(MSG_DEBUG, "P2P: Could not select "
"5 GHz channel for P2P group");
return -1;
@@ -4411,7 +4541,7 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq)
}
}
- if (freq > 0 && !p2p_supported_freq(wpa_s->global->p2p, freq)) {
+ if (freq > 0 && !p2p_supported_freq_go(wpa_s->global->p2p, freq)) {
wpa_printf(MSG_DEBUG, "P2P: The forced channel for GO "
"(%u MHz) is not supported for P2P uses",
freq);
@@ -4424,7 +4554,7 @@ static int wpas_p2p_select_go_freq(struct wpa_supplicant *wpa_s, int freq)
static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
struct p2p_go_neg_results *params,
- int freq, int ht40,
+ int freq, int ht40, int vht,
const struct p2p_channels *channels)
{
int res, *freqs;
@@ -4434,6 +4564,7 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
os_memset(params, 0, sizeof(*params));
params->role_go = 1;
params->ht40 = ht40;
+ params->vht = vht;
if (freq) {
if (!freq_included(channels, freq)) {
wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
@@ -4464,24 +4595,24 @@ static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
"frequency %d MHz", params->freq);
} else if (wpa_s->conf->p2p_oper_channel == 0 &&
wpa_s->best_overall_freq > 0 &&
- p2p_supported_freq(wpa_s->global->p2p,
- wpa_s->best_overall_freq) &&
+ p2p_supported_freq_go(wpa_s->global->p2p,
+ wpa_s->best_overall_freq) &&
freq_included(channels, wpa_s->best_overall_freq)) {
params->freq = wpa_s->best_overall_freq;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best overall "
"channel %d MHz", params->freq);
} else if (wpa_s->conf->p2p_oper_channel == 0 &&
wpa_s->best_24_freq > 0 &&
- p2p_supported_freq(wpa_s->global->p2p,
- wpa_s->best_24_freq) &&
+ p2p_supported_freq_go(wpa_s->global->p2p,
+ wpa_s->best_24_freq) &&
freq_included(channels, wpa_s->best_24_freq)) {
params->freq = wpa_s->best_24_freq;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 2.4 GHz "
"channel %d MHz", params->freq);
} else if (wpa_s->conf->p2p_oper_channel == 0 &&
wpa_s->best_5_freq > 0 &&
- p2p_supported_freq(wpa_s->global->p2p,
- wpa_s->best_5_freq) &&
+ p2p_supported_freq_go(wpa_s->global->p2p,
+ wpa_s->best_5_freq) &&
freq_included(channels, wpa_s->best_5_freq)) {
params->freq = wpa_s->best_5_freq;
wpa_printf(MSG_DEBUG, "P2P: Set GO freq based on best 5 GHz "
@@ -4600,13 +4731,15 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
* @wpa_s: Pointer to wpa_supplicant data from wpa_supplicant_add_iface()
* @persistent_group: Whether to create a persistent group
* @freq: Frequency for the group or 0 to indicate no hardcoding
+ * @ht40: Start GO with 40 MHz channel width
+ * @vht: Start GO with VHT support
* Returns: 0 on success, -1 on failure
*
* This function creates a new P2P group with the local end as the Group Owner,
* i.e., without using Group Owner Negotiation.
*/
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
- int freq, int ht40)
+ int freq, int ht40, int vht)
{
struct p2p_go_neg_results params;
@@ -4624,10 +4757,10 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
if (freq < 0)
return -1;
- if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, NULL))
+ if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, vht, NULL))
return -1;
if (params.freq &&
- !p2p_supported_freq(wpa_s->global->p2p, params.freq)) {
+ !p2p_supported_freq_go(wpa_s->global->p2p, params.freq)) {
wpa_printf(MSG_DEBUG, "P2P: The selected channel for GO "
"(%u MHz) is not supported for P2P uses",
params.freq);
@@ -4692,7 +4825,7 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s,
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
- int freq, int ht40,
+ int freq, int ht40, int vht,
const struct p2p_channels *channels,
int connection_timeout)
{
@@ -4727,7 +4860,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
if (freq < 0)
return -1;
- if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, channels))
+ if (wpas_p2p_init_go_params(wpa_s, &params, freq, ht40, vht, channels))
return -1;
params.role_go = 1;
@@ -5188,7 +5321,7 @@ int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr)
/* Invite to reinvoke a persistent group */
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
- int ht40, int pref_freq)
+ int ht40, int vht, int pref_freq)
{
enum p2p_invite_role role;
u8 *bssid = NULL;
@@ -5227,7 +5360,8 @@ int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
}
wpa_s->pending_invite_ssid_id = ssid->id;
- res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq);
+ res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+ role == P2P_INVITE_ROLE_GO);
if (res)
return res;
@@ -5259,6 +5393,7 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
wpa_s->p2p_persistent_go_freq = 0;
wpa_s->p2p_go_ht40 = 0;
+ wpa_s->p2p_go_vht = 0;
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
if (os_strcmp(wpa_s->ifname, ifname) == 0)
@@ -5311,7 +5446,8 @@ int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
return -1;
- res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq);
+ res = wpas_p2p_setup_freqs(wpa_s, freq, &force_freq, &pref_freq,
+ role == P2P_INVITE_ROLE_ACTIVE_GO);
if (res)
return res;
wpas_p2p_set_own_freq_preference(wpa_s, force_freq);
@@ -5668,6 +5804,11 @@ void wpas_p2p_update_config(struct wpa_supplicant *wpa_s)
wpa_printf(MSG_ERROR, "P2P: Preferred channel list "
"update failed");
}
+
+ if (p2p_set_no_go_freq(p2p, &wpa_s->conf->p2p_no_go_freq) < 0) {
+ wpa_printf(MSG_ERROR, "P2P: No GO channel list "
+ "update failed");
+ }
}
}
@@ -5839,19 +5980,20 @@ int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s)
void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s)
{
- struct p2p_channels chan;
+ struct p2p_channels chan, cli_chan;
if (wpa_s->global == NULL || wpa_s->global->p2p == NULL)
return;
os_memset(&chan, 0, sizeof(chan));
- if (wpas_p2p_setup_channels(wpa_s, &chan)) {
+ os_memset(&cli_chan, 0, sizeof(cli_chan));
+ if (wpas_p2p_setup_channels(wpa_s, &chan, &cli_chan)) {
wpa_printf(MSG_ERROR, "P2P: Failed to update supported "
"channel list");
return;
}
- p2p_update_channel_list(wpa_s->global->p2p, &chan);
+ p2p_update_channel_list(wpa_s->global->p2p, &chan, &cli_chan);
}
@@ -6130,7 +6272,8 @@ static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
0, 0, wpa_s->p2p_go_intent, wpa_s->p2p_connect_freq,
wpa_s->p2p_persistent_id,
wpa_s->p2p_pd_before_go_neg,
- wpa_s->p2p_go_ht40);
+ wpa_s->p2p_go_ht40,
+ wpa_s->p2p_go_vht);
}
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 64c5857c..b462d1b3 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -24,7 +24,7 @@ int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
const char *pin, enum p2p_wps_method wps_method,
int persistent_group, int auto_join, int join,
int auth, int go_intent, int freq, int persistent_id,
- int pd, int ht40);
+ int pd, int ht40, int vht);
void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
unsigned int freq, unsigned int duration);
void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
@@ -35,10 +35,10 @@ int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
#endif
int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
- int freq, int ht40);
+ int freq, int ht40, int vht);
int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid, int addr_allocated,
- int freq, int ht40,
+ int freq, int ht40, int vht,
const struct p2p_channels *channels,
int connection_timeout);
struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
@@ -115,7 +115,7 @@ int wpas_p2p_service_del_upnp(struct wpa_supplicant *wpa_s, u8 version,
int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr);
int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
- int ht40, int pref_freq);
+ int ht40, int vht, int pref_freq);
int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
const u8 *peer_addr, const u8 *go_dev_addr);
void wpas_p2p_completed(struct wpa_supplicant *wpa_s);
@@ -156,6 +156,8 @@ void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s);
int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
struct hostapd_hw_modes *mode, u8 channel);
+int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
+ struct hostapd_hw_modes *mode, u8 channel);
unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s);
void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
const u8 *p2p_dev_addr,
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 8c900c2d..66c4962a 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -615,7 +615,9 @@ static char ** wpa_cli_complete_set(const char *str, int pos)
"p2p_oper_reg_class", "p2p_oper_channel",
"p2p_go_intent", "p2p_ssid_postfix", "persistent_reconnect",
"p2p_intra_bss", "p2p_group_idle", "p2p_pref_chan",
+ "p2p_no_go_freq",
"p2p_go_ht40", "p2p_disabled", "p2p_no_group_iface",
+ "p2p_go_vht",
"p2p_ignore_shared_freq", "country", "bss_max_count",
"bss_expiration_age", "bss_expiration_scan_count",
"filter_ssids", "filter_rssi", "max_num_sta",
@@ -627,7 +629,7 @@ static char ** wpa_cli_complete_set(const char *str, int pos)
"sae_groups", "dtim_period", "beacon_int", "ap_vendor_elements",
"ignore_old_scan_res", "freq_list", "external_sim"
};
- int i, num_fields = sizeof(fields) / sizeof(fields[0]);
+ int i, num_fields = ARRAY_SIZE(fields);
if (arg == 1) {
char **res = os_calloc(num_fields + 1, sizeof(char *));
@@ -2112,7 +2114,7 @@ static char ** wpa_cli_complete_p2p_set(const char *str, int pos)
"disc_int",
"per_sta_psk",
};
- int i, num_fields = sizeof(fields) / sizeof(fields[0]);
+ int i, num_fields = ARRAY_SIZE(fields);
if (arg == 1) {
char **res = os_calloc(num_fields + 1, sizeof(char *));
@@ -2954,7 +2956,7 @@ static char ** wpa_list_cmd_list(void)
int i, count;
struct cli_txt_entry *e;
- count = sizeof(wpa_cli_commands) / sizeof(wpa_cli_commands[0]);
+ count = ARRAY_SIZE(wpa_cli_commands);
count += dl_list_len(&p2p_groups);
count += dl_list_len(&ifnames);
res = os_calloc(count + 1, sizeof(char *));
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 6bcf6302..41ae8f16 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -217,7 +217,7 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
int sec, int usec)
{
- if (wpa_s->conf && wpa_s->conf->ap_scan == 0 &&
+ if (wpa_s->conf->ap_scan == 0 &&
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
return;
@@ -293,11 +293,10 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
EAPOL_REQUIRE_KEY_BROADCAST;
}
- if (wpa_s->conf && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)
eapol_conf.required_keys = 0;
}
- if (wpa_s->conf)
- eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
+ eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
eapol_conf.workaround = ssid->eap_workaround;
eapol_conf.eap_disabled =
!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
@@ -678,6 +677,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
wpa_drv_set_supp_port(wpa_s, 1);
#endif /* IEEE8021X_EAPOL */
wpa_s->after_wps = 0;
+ wpa_s->known_wps_freq = 0;
#ifdef CONFIG_P2P
wpas_p2p_completed(wpa_s);
#endif /* CONFIG_P2P */
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index eea7be9a..da536cb2 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -639,6 +639,7 @@ struct wpa_supplicant {
unsigned int p2p_fallback_to_go_neg:1;
unsigned int p2p_pd_before_go_neg:1;
unsigned int p2p_go_ht40:1;
+ unsigned int p2p_go_vht:1;
unsigned int user_initiated_pd:1;
unsigned int p2p_go_group_formation_completed:1;
int p2p_first_connection_timeout;
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 0d754640..4c40dac4 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -883,6 +883,7 @@ static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
struct wpa_ssid *ssid, *remove_ssid = NULL, *prev_current;
wpa_s->after_wps = 0;
+ wpa_s->known_wps_freq = 0;
prev_current = wpa_s->current_ssid;