diff options
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, ¶ms, freq, ht40, NULL)) + if (wpas_p2p_init_go_params(wpa_s, ¶ms, 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, ¶ms, freq, ht40, channels)) + if (wpas_p2p_init_go_params(wpa_s, ¶ms, 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; |