Signed-off-by: Shivani Baranwal <quic_shivbara@xxxxxxxxxxx> --- src/ap/hostapd.c | 15 ++++- src/ap/hostapd.h | 3 + src/ap/hw_features.c | 3 +- src/common/ieee802_11_common.c | 14 ++--- src/common/ieee802_11_defs.h | 9 +++ src/p2p/p2p.c | 125 +++++++++++++++++++++++++++++++++++++- src/p2p/p2p.h | 22 +++++++ src/p2p/p2p_build.c | 44 ++++++++++++++ src/p2p/p2p_go_neg.c | 68 +++++++++++++++++++++ src/p2p/p2p_group.c | 11 ++++ src/p2p/p2p_i.h | 20 ++++++ src/p2p/p2p_parse.c | 9 +++ src/p2p/p2p_utils.c | 50 +++++++++++++++ wpa_supplicant/ap.c | 1 + wpa_supplicant/config.c | 2 + wpa_supplicant/config.h | 2 + wpa_supplicant/ctrl_iface.c | 5 ++ wpa_supplicant/events.c | 11 ++++ wpa_supplicant/p2p_supplicant.c | 52 ++++++++++++++-- wpa_supplicant/p2p_supplicant.h | 7 +++ wpa_supplicant/wpa_supplicant_i.h | 1 + 21 files changed, 458 insertions(+), 16 deletions(-) diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index a0ac3a8..3cb132c 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -2495,8 +2495,17 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface, iface->conf->channel, iface->freq); #ifdef NEED_AP_MLME - /* Handle DFS only if it is not offloaded to the driver */ - if (!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)) { + if (iface->assisted_dfs_go) { + if (!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)) { + wpa_printf(MSG_DEBUG, + "Fail: Offload not supported for assisted DFS P2P GO"); + goto fail; + } + // FIXME: Check with shivani if this is correct or not + wpa_printf(MSG_DEBUG, + "Request for Assisted DFS P2P GO"); + } else if (!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)) { + /* Handle DFS only if it is not offloaded to the driver */ /* Check DFS */ res = hostapd_handle_dfs(iface); if (res <= 0) { @@ -2645,7 +2654,7 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface, } if ((iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) && - !res_dfs_offload) { + !res_dfs_offload && !iface->assisted_dfs_go) { /* * If freq is DFS, and DFS is offloaded to the driver, then wait * for CAC to complete. diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index dcf395c..66239dc 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -711,6 +711,9 @@ struct hostapd_iface { bool is_no_ir; bool is_ch_switch_dfs; /* Channel switch from ACS to DFS */ + + /* P2P GO in assisted DFS mode */ + bool assisted_dfs_go; }; /* hostapd.c */ diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c index c455660..23b193b 100644 --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c @@ -142,7 +142,8 @@ int hostapd_get_hw_features(struct hostapd_iface *iface) } else if (((feature->channels[j].flag & HOSTAPD_CHAN_RADAR) && !(iface->drv_flags & - WPA_DRIVER_FLAGS_DFS_OFFLOAD)) || + WPA_DRIVER_FLAGS_DFS_OFFLOAD) && + !iface->assisted_dfs_go) || (feature->channels[j].flag & HOSTAPD_CHAN_NO_IR)) { feature->channels[j].flag |= diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index b16564d..2c22016 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -2066,7 +2066,7 @@ int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes, */ int is_dfs_global_op_class(u8 op_class) { - return (op_class >= 118) && (op_class <= 123); + return (op_class >= 118) && (op_class <= 130); } @@ -2422,12 +2422,12 @@ const struct oper_class_map global_op_class[] = { { HOSTAPD_MODE_IEEE80211A, 115, 36, 48, 4, BW20, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 116, 36, 44, 8, BW40PLUS, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS, P2P_SUPP }, - { HOSTAPD_MODE_IEEE80211A, 118, 52, 64, 4, BW20, NO_P2P_SUPP }, - { HOSTAPD_MODE_IEEE80211A, 119, 52, 60, 8, BW40PLUS, NO_P2P_SUPP }, - { HOSTAPD_MODE_IEEE80211A, 120, 56, 64, 8, BW40MINUS, NO_P2P_SUPP }, - { HOSTAPD_MODE_IEEE80211A, 121, 100, 144, 4, BW20, NO_P2P_SUPP }, - { HOSTAPD_MODE_IEEE80211A, 122, 100, 140, 8, BW40PLUS, NO_P2P_SUPP }, - { HOSTAPD_MODE_IEEE80211A, 123, 104, 144, 8, BW40MINUS, NO_P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 118, 52, 64, 4, BW20, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 119, 52, 60, 8, BW40PLUS, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 120, 56, 64, 8, BW40MINUS, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 121, 100, 144, 4, BW20, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 122, 100, 140, 8, BW40PLUS, P2P_SUPP }, + { HOSTAPD_MODE_IEEE80211A, 123, 104, 144, 8, BW40MINUS, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 124, 149, 161, 4, BW20, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 125, 149, 177, 4, BW20, P2P_SUPP }, { HOSTAPD_MODE_IEEE80211A, 126, 149, 173, 8, BW40PLUS, P2P_SUPP }, diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index db1033a..7a46e77 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -1754,6 +1754,7 @@ enum p2p_attr_id { P2P_ATTR_FEATURE_CAPABILITY = 27, P2P_ATTR_PERSISTENT_GROUP = 28, P2P_ATTR_CAPABILITY_EXTENSION = 29, + P2P_ATTR_WLAN_AP_INFORMATION = 30, P2P_ATTR_DEVICE_IDENTITY_KEY = 31, P2P_ATTR_DEVICE_IDENTITY_RESOLUTION = 32, P2P_ATTR_PAIRING_AND_BOOTSTRAPPING = 33, @@ -3106,6 +3107,14 @@ struct ieee80211_s1g_beacon_compat { le32 tsf_completion; } STRUCT_PACKED; +struct ieee80211_dfs_ap_info_list { + u8 flag; + u8 bssid[ETH_ALEN]; + u8 country[3]; + u8 op_class; + u8 op_chan; +}; + #ifdef _MSC_VER #pragma pack(pop) #endif /* _MSC_VER */ diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 59a15a8..7cd1768 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -1431,7 +1431,15 @@ static int p2p_prepare_channel_pref(struct p2p_data *p2p, 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) { + + if (p2p->cfg->is_p2p_dfs_chan && + p2p->cfg->is_p2p_dfs_chan(p2p->cfg->cb_ctx, freq, 0, 0)) { + if (ieee80211_freq_to_channel_ext(freq, 0, CONF_OPER_CHWIDTH_80MHZ, + &op_class, &op_channel) == NUM_HOSTAPD_MODES) { + p2p_dbg(p2p, "Unsupported frequency %u MHz", freq); + return -1; + } + } else if (p2p_freq_to_channel(freq, &op_class, &op_channel) < 0) { p2p_dbg(p2p, "Unsupported frequency %u MHz", freq); return -1; } @@ -1570,6 +1578,8 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p) int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev, unsigned int force_freq, unsigned int pref_freq, int go) { + struct p2p_channels p2p_chanlist; + p2p_dbg(p2p, "Prepare channel - force_freq=%u pref_freq=%u go=%d", force_freq, pref_freq, go); if (force_freq || pref_freq) { @@ -1579,6 +1589,18 @@ int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev, } else { p2p_prepare_channel_best(p2p); } + + if (p2p->cfg->is_p2p_dfs_chan && + p2p->cfg->is_p2p_dfs_chan(p2p->cfg->cb_ctx, 0, + p2p->op_reg_class, p2p->op_channel)) { + p2p_dfs_channel_filter(p2p, &p2p->channels, p2p->dfs_ap_list, + p2p->num_dfs_ap, &p2p_chanlist); + p2p_channels_dump(p2p, "channel list after filtering DFS " + " channels with WLAN AP info attr channles", + &p2p_chanlist); + p2p_copy_channels(&p2p->channels, &p2p_chanlist, p2p->allow_6ghz); + } + p2p_channels_dump(p2p, "prepared channels", &p2p->channels); if (go) p2p_channels_remove_freqs(&p2p->channels, &p2p->no_go_freq); @@ -2806,6 +2828,20 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf, p2p_buf_add_device_info(tmp, p2p, peer); p2p_buf_update_ie_hdr(tmp, lpos); + if (p2p->cfg->is_p2p_dfs_chan && + p2p->cfg->is_p2p_dfs_chan(p2p->cfg->cb_ctx, 0, p2p->op_reg_class, + p2p->op_channel) && + !is_p2p_dfs_owner(p2p)) { + struct wpabuf *p2p2_ie; + + p2p2_ie = wpabuf_alloc(255); + if (!p2p2_ie) + return -1; + + p2p_group_build_p2p2_ie(p2p, p2p2_ie, 0); + tmp = wpabuf_concat(p2p2_ie, tmp); + } + tmplen = wpabuf_len(tmp); if (tmplen > len) res = -1; @@ -3077,6 +3113,91 @@ bool is_p2p_6ghz_disabled(struct p2p_data *p2p) return false; } + +bool is_p2p_dfs_chan_enabled(struct p2p_data *p2p) +{ + if (p2p) + return p2p->cfg->dfs_chan_enable; + return false; +} + + +bool is_p2p_dfs_owner(struct p2p_data *p2p) +{ + if (p2p) + return p2p->cfg->dfs_owner; + return false; +} + + +void p2p_remove_wlan_ap_info(struct p2p_data *p2p, u8 val) +{ + p2p->cfg->remove_wlan_ap_info = val; +} + + +struct ieee80211_dfs_ap_info_list * p2p_dfs_get_ap_info(struct p2p_data *p2p, + const u8 *bssid) +{ + size_t i; + + if (!p2p->dfs_ap_list) + return NULL; + + for (i = 0; i < p2p->num_dfs_ap; i++) { + struct ieee80211_dfs_ap_info_list *dfs_ap = + &p2p->dfs_ap_list[i]; + if (ether_addr_equal(dfs_ap->bssid, bssid)) + return dfs_ap; + } + return NULL; +} + + +void p2p_update_dfs_ap_info(struct p2p_data *p2p, const u8 *bssid, int freq, + int flag, bool disconnect_evt) +{ + struct ieee80211_dfs_ap_info_list *dfs_ap; + + dfs_ap = p2p_dfs_get_ap_info(p2p, bssid); + + if (dfs_ap) { + wpa_printf(MSG_DEBUG, "Update the existing DFS AP info"); + } else { + dfs_ap = os_realloc_array(p2p->dfs_ap_list, p2p->num_dfs_ap + 1, + sizeof(struct ieee80211_dfs_ap_info_list)); + if (!dfs_ap) { + wpa_printf(MSG_DEBUG, "Unable to allocate dfs_ap memory"); + return; + } + + p2p->dfs_ap_list = dfs_ap; + dfs_ap = &p2p->dfs_ap_list[p2p->num_dfs_ap]; + p2p->num_dfs_ap++; + os_memset(dfs_ap, 0, sizeof(*dfs_ap)); + } + + if (disconnect_evt) + dfs_ap->flag = 0; + + /* skip if flag is already set by assoc event */ + if (!dfs_ap->flag) + dfs_ap->flag = flag; + + os_memcpy(dfs_ap->bssid, bssid, ETH_ALEN); + + //TO-DO: update country string correctly + dfs_ap->country[0] = 0; + dfs_ap->country[1] = 0; + + dfs_ap->country[2] = 0x04; + ieee80211_freq_to_channel_ext(freq, 0, + CONF_OPER_CHWIDTH_80MHZ, + &dfs_ap->op_class, + &dfs_ap->op_chan); +} + + int p2p_pairing_info_init(struct p2p_data *p2p) { struct p2p_pairing_info *pairing_info; @@ -3231,6 +3352,8 @@ void p2p_deinit(struct p2p_data *p2p) os_free(p2p->no_go_freq.range); p2p_service_flush_asp(p2p); p2p_pairing_info_deinit(p2p); + if (p2p->dfs_ap_list) + os_free(p2p->dfs_ap_list); os_free(p2p); } diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index 5d798a0..b40fef6 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -735,6 +735,11 @@ struct p2p_config { bool dfs_owner; /** + * dfs_chan_enable - Enable p2p Go to operate on dfs channel + */ + bool dfs_chan_enable; + + /** * twt_power_mgmt - Enable TWT based power mgmt for P2P */ bool twt_power_mgmt; @@ -745,6 +750,10 @@ struct p2p_config { */ u16 comeback_after; + /** + * remove_wlan_ap_info - Flag not to include wlan ap info in frames + */ + u8 remove_wlan_ap_info; /** * cb_ctx - Context to use with callback functions @@ -1387,6 +1396,14 @@ struct p2p_config { * Returns: 0 on success, -1 on failure */ int (*pasn_parse_encrypted_data)(void *ctx, const u8 *data, size_t len); + + /** + * + * is_p2p_dfs_chan - DFS channel check + * + * To check if a channel is DFS channel or not. + */ + int (*is_p2p_dfs_chan)(void *ctx, int freq, int op_class, int op_chan); }; @@ -2724,4 +2741,9 @@ void p2p_pasn_pmksa_set_pmk(struct p2p_data *p2p, const u8 *src, const u8 *dst, void p2p_set_store_pasn_ptk(struct p2p_data *p2p, u8 val); void p2p_pasn_store_ptk(struct p2p_data *p2p, struct wpa_ptk *ptk); int p2p_pasn_get_ptk(struct p2p_data *p2p, const u8 **buf, size_t *buf_len); +bool is_p2p_dfs_chan_enabled(struct p2p_data *p2p); +bool is_p2p_dfs_owner(struct p2p_data *p2p); +void p2p_remove_wlan_ap_info(struct p2p_data *p2p, u8 val); +void p2p_update_dfs_ap_info(struct p2p_data *p2p, const u8 *bssid, int freq, + int flag, bool disconnect_evt); #endif /* P2P_H */ diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c index f505ad9..c76918c 100644 --- a/src/p2p/p2p_build.c +++ b/src/p2p/p2p_build.c @@ -1057,3 +1057,47 @@ struct wpabuf *p2p_encaps_p2p_vendor_ie(struct p2p_data *p2p, return ie; } + +void p2p_buf_add_wlan_ap_info(struct wpabuf *buf, + struct ieee80211_dfs_ap_info_list *dfs_ap_list, + size_t list_size) +{ + u8 *len; + size_t i, size; + + if (!list_size) + return; + + wpabuf_put_u8(buf, P2P_ATTR_WLAN_AP_INFORMATION); + /* IE length to be filled */ + len = wpabuf_put(buf, 2); + + for (i = 0; i < list_size; i++) { + if (dfs_ap_list[i].flag != 1) + continue; + + wpabuf_put_u8(buf, dfs_ap_list[i].flag); + wpabuf_put_data(buf, dfs_ap_list[i].bssid, ETH_ALEN); + wpabuf_put_data(buf, dfs_ap_list[i].country, 3); + wpabuf_put_u8(buf, dfs_ap_list[i].op_class); + wpabuf_put_u8(buf, dfs_ap_list[i].op_chan); + } + + if (list_size > 4) + size = 4; + else + size = list_size; + + for (i = 0; i < size; i++) { + if (dfs_ap_list[i].flag == 1) + continue; + wpabuf_put_u8(buf, dfs_ap_list[i].flag); + wpabuf_put_data(buf, dfs_ap_list[i].bssid, ETH_ALEN); + wpabuf_put_data(buf, dfs_ap_list[i].country, 3); + wpabuf_put_u8(buf, dfs_ap_list[i].op_class); + wpabuf_put_u8(buf, dfs_ap_list[i].op_chan); + } + + /* Update attribute length */ + WPA_PUT_LE16(len, (u8 *)wpabuf_put(buf, 0) - len - 2); +} diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index 1f6923d..3129d78 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -138,6 +138,7 @@ static const char * p2p_wps_method_str(enum p2p_wps_method wps_method) struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, struct p2p_device *peer) { + u8 *len; u8 group_capab; size_t extra = 0; u16 pw_id; @@ -227,6 +228,15 @@ struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]) wpabuf_put_buf(buf2, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]); + + if (p2p->cfg->is_p2p_dfs_chan && + p2p->cfg->is_p2p_dfs_chan(p2p->cfg->cb_ctx, 0, + p2p->op_reg_class, p2p->op_channel)) { + len = p2p_buf_add_p2p2_ie_hdr(buf2); + p2p_buf_add_wlan_ap_info(buf2, p2p->dfs_ap_list, + p2p->num_dfs_ap); + p2p_buf_update_p2p2_ie_hdr(buf2, len); + } buf = wpabuf_concat(buf2, buf); return buf; @@ -298,6 +308,7 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, u8 dialog_token, u8 status, u8 tie_breaker) { + u8 *len; u8 group_capab; size_t extra = 0; u16 pw_id; @@ -415,6 +426,15 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]) wpabuf_put_buf(buf2, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]); + + if (p2p->cfg->is_p2p_dfs_chan && + p2p->cfg->is_p2p_dfs_chan(p2p->cfg->cb_ctx, 0, + p2p->op_reg_class, p2p->op_channel)) { + len = p2p_buf_add_p2p2_ie_hdr(buf2); + p2p_buf_add_wlan_ap_info(buf2, p2p->dfs_ap_list, + p2p->num_dfs_ap); + p2p_buf_update_p2p2_ie_hdr(buf2, len); + } buf = wpabuf_concat(buf2, buf); return buf; @@ -1089,6 +1109,24 @@ skip: */ p2p_check_pref_chan(p2p, go, dev, &msg); + if (msg.wlan_ap_info) { + u8 *pos = (u8 *)msg.wlan_ap_info, match = 0, i; + if (p2p->cfg->is_p2p_dfs_chan && + p2p->cfg->is_p2p_dfs_chan(p2p->cfg->cb_ctx, 0, + p2p->op_reg_class, + p2p->op_channel)) { + for (i = 0; i < msg.wlan_ap_info_len; i += 12) { + if (*(pos + 10) == p2p->op_reg_class && + *(pos + 11) == p2p->op_channel) { + match = 1; + break; + } + } + if (match == 0) + goto fail; + } + } + if (msg.config_timeout) { dev->go_timeout = msg.config_timeout[0]; dev->client_timeout = msg.config_timeout[1]; @@ -1176,6 +1214,7 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p, u8 dialog_token, u8 status, const u8 *resp_chan, int go) { + u8 *len; struct p2p_channels res; u8 group_capab; size_t extra = 0; @@ -1246,6 +1285,15 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p, if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]) wpabuf_put_buf(buf2, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]); + if (p2p->cfg->is_p2p_dfs_chan && + p2p->cfg->is_p2p_dfs_chan(p2p->cfg->cb_ctx, 0, + p2p->op_reg_class, p2p->op_channel)) { + len = p2p_buf_add_p2p2_ie_hdr(buf2); + p2p_buf_add_wlan_ap_info(buf2, p2p->dfs_ap_list, + p2p->num_dfs_ap); + p2p_buf_update_p2p2_ie_hdr(buf2, len); + } + buf = wpabuf_concat(buf2, buf); return buf; @@ -1485,6 +1533,26 @@ skip: if (go) p2p_check_pref_chan(p2p, go, dev, &msg); + if (msg.wlan_ap_info) { + u16 match = 0, i; + const u8 *pos = msg.wlan_ap_info; + + if (p2p->cfg->is_p2p_dfs_chan && + p2p->cfg->is_p2p_dfs_chan(p2p->cfg->cb_ctx, 0, + p2p->op_reg_class, + p2p->op_channel)) { + for (i = 0; i < msg.wlan_ap_info_len; i += 12) { + if (*(pos + 10) == p2p->op_reg_class && + *(pos + 11) == p2p->op_channel) { + match = 1; + break; + } + } + if (match == 0) + goto fail; + } + } + p2p_set_state(p2p, P2P_GO_NEG); p2p_clear_timeout(p2p); diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c index 4822c28..d07f41e 100644 --- a/src/p2p/p2p_group.c +++ b/src/p2p/p2p_group.c @@ -217,6 +217,17 @@ struct wpabuf * p2p_group_build_p2p2_ie(struct p2p_data *p2p, wpabuf_put_be32(p2p2_ie, P2P2_IE_VENDOR_TYPE); wpa_printf(MSG_DEBUG, "P2P: * P2P2 IE header"); p2p_buf_add_pcea(p2p2_ie, p2p); + if (p2p->cfg->remove_wlan_ap_info) + goto out; + + if (p2p->cfg->is_p2p_dfs_chan && + p2p->cfg->is_p2p_dfs_chan(p2p->cfg->cb_ctx, freq, p2p->op_reg_class, + p2p->op_channel) && + !is_p2p_dfs_owner(p2p)) { + p2p_buf_add_wlan_ap_info(p2p2_ie, p2p->dfs_ap_list, + p2p->num_dfs_ap); + } +out: *len = (u8 *)wpabuf_put(p2p2_ie, 0) - len - 1; return p2p2_ie; diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 32a8421..54de28b 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -691,6 +691,16 @@ struct p2p_data { * pasn ptk length */ size_t pasn_ptk_len; + + /** + * list of DFS APs + */ + struct ieee80211_dfs_ap_info_list *dfs_ap_list; + + /** + * num of DFS APs + */ + size_t num_dfs_ap; }; /** @@ -809,6 +819,9 @@ struct p2p_message { const u8 *dira; size_t dira_len; + + const u8 *wlan_ap_info; + size_t wlan_ap_info_len; }; @@ -1079,6 +1092,13 @@ void p2p_pref_channel_filter(const struct p2p_channels *a, void p2p_sd_query_cb(struct p2p_data *p2p, int success); void p2p_pasn_initialize(struct p2p_data *p2p, struct p2p_device *dev, const u8 *addr, int freq, bool verify); +void p2p_dfs_channel_filter(struct p2p_data *p2p, + const struct p2p_channels *p2p_chan, + const struct ieee80211_dfs_ap_info_list *ap_list, + size_t num_dfs_ap, struct p2p_channels *res); +void p2p_buf_add_wlan_ap_info(struct wpabuf *buf, + struct ieee80211_dfs_ap_info_list *dfs_ap_list, + size_t list_size); void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...) PRINTF_FORMAT(2, 3); diff --git a/src/p2p/p2p_parse.c b/src/p2p/p2p_parse.c index de2a43f..d863b72 100644 --- a/src/p2p/p2p_parse.c +++ b/src/p2p/p2p_parse.c @@ -457,6 +457,15 @@ static int p2p_parse_attribute(u8 id, const u8 *data, u16 len, msg->dira_len = len; wpa_printf(MSG_DEBUG, "P2P: * DIRA (length=%u)", len); break; + case P2P_ATTR_WLAN_AP_INFORMATION: + if (len < 1) { + wpa_printf(MSG_DEBUG, "P2P: Too short WLAN AP info (length %d)", + len); + return -1; + } + msg->wlan_ap_info = data; + msg->wlan_ap_info_len = len; + break; default: wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d " "(length %d)", id, len); diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c index c1f0084..35cbb16 100644 --- a/src/p2p/p2p_utils.c +++ b/src/p2p/p2p_utils.c @@ -611,3 +611,53 @@ void p2p_pref_channel_filter(const struct p2p_channels *p2p_chan, res_reg->reg_class = reg->reg_class; } } + + +static int +p2p_check_dfs_channel(int channel, u8 op_class, + const struct ieee80211_dfs_ap_info_list *ap_list, + unsigned int num_dfs_ap) +{ + unsigned int i; + + for (i = 0; i < num_dfs_ap; i++) { + if (op_class == ap_list[i].op_class && + channel == ap_list[i].op_chan) + return 0; + } + return -1; +} + + +void p2p_dfs_channel_filter(struct p2p_data *p2p, + const struct p2p_channels *p2p_chan, + const struct ieee80211_dfs_ap_info_list *ap_list, + size_t num_dfs_ap, struct p2p_channels *res) +{ + size_t i, j; + + os_memset(res, 0, sizeof(*res)); + + for (i = 0; i < p2p_chan->reg_classes; i++) { + const struct p2p_reg_class *reg = &p2p_chan->reg_class[i]; + struct p2p_reg_class *res_reg = &res->reg_class[i]; + + for (j = 0; j < reg->channels; j++) { + if (p2p->cfg->is_p2p_dfs_chan(p2p->cfg->cb_ctx, 0, + reg->reg_class, + reg->channel[j]) && + p2p_check_dfs_channel(reg->channel[j], + reg->reg_class, ap_list, + num_dfs_ap) < 0) + continue; + + res_reg->channel[res_reg->channels++] = + reg->channel[j]; + } + + if (res_reg->channels == 0) + continue; + res->reg_classes++; + res_reg->reg_class = reg->reg_class; + } +} diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c index 69a0e5e..9ca266a 100644 --- a/wpa_supplicant/ap.c +++ b/wpa_supplicant/ap.c @@ -1072,6 +1072,7 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s, hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask; hapd_iface->extended_capa_len = wpa_s->extended_capa_len; hapd_iface->drv_max_acl_mac_addrs = wpa_s->drv_max_acl_mac_addrs; + hapd_iface->assisted_dfs_go = wpa_s->assisted_dfs_go; wpa_s->ap_iface->conf = conf = hostapd_config_defaults(); if (conf == NULL) { diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index f9d34b2..da37d88 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -5549,6 +5549,8 @@ static const struct global_parse_data global_fields[] = { { FUNC(p2p_device_persistent_mac_addr), 0 }, { INT(p2p_interface_random_mac_addr), 0 }, { INT(p2p_6ghz_disable), 0 }, + { INT(p2p_dfs_chan_enable), 0 }, + { INT(p2p_dfs_owner), 0 }, #endif /* CONFIG_P2P */ { FUNC(country), CFG_CHANGED_COUNTRY }, { INT(bss_max_count), 0 }, diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 3333125..11b83f9 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -909,6 +909,8 @@ struct wpa_config { int p2p_optimize_listen_chan; int p2p_6ghz_disable; + int p2p_dfs_chan_enable; + int p2p_dfs_owner; struct wpabuf *wps_vendor_ext_m1; diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 9c9e9a7..556f203 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -7753,6 +7753,11 @@ static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd) return 0; } + if (os_strcmp(cmd, "remove_wlan_ap_info") == 0) { + p2p_remove_wlan_ap_info(wpa_s->global->p2p, atoi(param)); + return 0; + } + wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'", cmd); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 1c7992e..d70cb88 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -391,6 +391,7 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s) sme_clear_on_disassoc(wpa_s); wpa_s->current_bss = NULL; wpa_s->assoc_freq = 0; + wpa_s->assisted_dfs_go = 0; if (bssid_changed) wpas_notify_bssid_changed(wpa_s); @@ -2588,6 +2589,7 @@ static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s, wpas_notify_scan_done(wpa_s, 1); + wpas_p2p_update_dfs_ap_info_list(wpa_s, scan_res); if (ap) { wpa_dbg(wpa_s, MSG_DEBUG, "Ignore scan results in AP mode"); #ifdef CONFIG_AP @@ -3799,6 +3801,12 @@ no_pfs: } wpa_s->assoc_freq = data->assoc_info.freq; + if (ieee80211_is_dfs(wpa_s->assoc_freq, wpa_s->hw.modes, + wpa_s->hw.num_modes)) { + wpa_s->assisted_dfs_go = 1; + p2p_update_dfs_ap_info(wpa_s->global->p2p, bssid, + wpa_s->assoc_freq, 1, 0); + } #ifndef CONFIG_NO_ROBUST_AV wpas_handle_assoc_resp_qos_mgmt(wpa_s, data->assoc_info.resp_ies, @@ -4728,6 +4736,9 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s, wpa_sm_notify_disassoc(wpa_s->wpa); ptksa_cache_flush(wpa_s->ptksa, wpa_s->bssid, WPA_CIPHER_NONE); + p2p_update_dfs_ap_info(wpa_s->global->p2p, bssid, + wpa_s->assoc_freq, 0, 1); + if (locally_generated) wpa_s->disconnect_reason = -reason_code; else diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 394beef..22778c4 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -2539,6 +2539,7 @@ wpas_p2p_init_group_interface(struct wpa_supplicant *wpa_s, int go) wpas_p2p_clone_config(group_wpa_s, wpa_s); group_wpa_s->p2p2 = wpa_s->p2p2; + group_wpa_s->assisted_dfs_go = wpa_s->assisted_dfs_go; if (wpa_s->conf->p2p_interface_random_mac_addr) { if (wpa_drv_set_mac_addr(group_wpa_s, @@ -4234,8 +4235,11 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s, const struct oper_class_map *o = &global_op_class[op]; unsigned int ch; struct p2p_reg_class *reg = NULL, *cli_reg = NULL; + bool check_dfs_supported = + (is_p2p_dfs_chan_enabled(wpa_s->global->p2p) && + is_dfs_global_op_class(o->op_class)); - if (o->p2p == NO_P2P_SUPP || + if ((!check_dfs_supported && o->p2p == NO_P2P_SUPP) || (is_6ghz_op_class(o->op_class) && p2p_disable_6ghz)) continue; @@ -4253,10 +4257,11 @@ static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s, if ((o->op_class >= 128 && o->op_class <= 130) && ch < 149 && ch + o->inc > 149) ch = 149; - + //FIXME + wpa_s->p2p_go_allow_dfs = 1; res = wpas_p2p_verify_channel(wpa_s, mode, o->op_class, ch, o->bw); - if (res == ALLOWED) { + if (res == ALLOWED || (res == RADAR && check_dfs_supported)) { if (reg == NULL) { if (cla == P2P_MAX_REG_CLASSES) continue; @@ -5449,6 +5454,19 @@ int wpas_p2p_mac_setup(struct wpa_supplicant *wpa_s) } +static int wpas_p2p_dfs_chan(void *ctx, int freq, int op_class, int op_chan) +{ + struct wpa_supplicant *wpa_s = ctx; + + if (freq == 0) + freq = ieee80211_chan_to_freq(NULL, op_class, op_chan); + if (ieee80211_is_dfs(freq, wpa_s->hw.modes, wpa_s->hw.num_modes)) + return 1; + + return 0; +} + + /** * wpas_p2p_init - Initialize P2P module for %wpa_supplicant * @global: Pointer to global data from wpa_supplicant_init() @@ -5520,6 +5538,11 @@ int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s) p2p.pasn_update_extra_ies = wpas_p2p_pasn_update_extra_ies; p2p.pasn_parse_encrypted_data = wpas_p2p_pasn_parse_encrypted_data; #endif /* CONFIG_PASN */ + p2p.is_p2p_dfs_chan = wpas_p2p_dfs_chan; + // FIXME: Dont hardcode dfs_chan_enable +// p2p.dfs_chan_enable = wpa_s->conf->p2p_dfs_chan_enable; + p2p.dfs_chan_enable = 1; + p2p.dfs_owner = wpa_s->conf->p2p_dfs_owner; os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN); os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN); p2p.dev_name = wpa_s->conf->device_name; @@ -6460,7 +6483,7 @@ static int wpas_p2p_setup_freqs(struct wpa_supplicant *wpa_s, int freq, else ret = p2p_supported_freq_cli(wpa_s->global->p2p, freq); if (!ret) { - if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) && + if (is_p2p_dfs_chan_enabled(wpa_s->global->p2p) && ieee80211_is_dfs(freq, wpa_s->hw.modes, wpa_s->hw.num_modes)) { /* @@ -11171,3 +11194,24 @@ int wpas_p2p_get_pasn_ptk(struct wpa_supplicant *wpa_s, const u8 **ptk, return p2p_pasn_get_ptk(p2p, ptk, ptk_len); } #endif /* CONFIG_PASN */ + +void wpas_p2p_update_dfs_ap_info_list(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *scan_res) +{ + size_t i; + + for (i = 0; i < scan_res->num; i++) { + if (!ieee80211_is_dfs(scan_res->res[i]->freq, wpa_s->hw.modes, + wpa_s->hw.num_modes)) + continue; + if (scan_res->res[i]->flags & BIT(5)) { + p2p_update_dfs_ap_info(wpa_s->global->p2p, + scan_res->res[i]->bssid, + scan_res->res[i]->freq, 1, 0); + } else { + p2p_update_dfs_ap_info(wpa_s->global->p2p, + scan_res->res[i]->bssid, + scan_res->res[i]->freq, 0, 0); + } + } +} diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 3dcc9e3..aafe647 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -236,6 +236,8 @@ int wpas_p2p_pasn_auth_rx(struct wpa_supplicant *wpa_s, int wpas_p2p_remove_all_identity(struct wpa_supplicant *wpa_s); int wpas_p2p_get_pasn_ptk(struct wpa_supplicant *wpa_s, const u8 **ptk, size_t *ptk_len); +void wpas_p2p_update_dfs_ap_info_list(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *scan_res); #else /* CONFIG_P2P */ static inline int @@ -385,6 +387,11 @@ static inline int wpas_p2p_get_pasn_ptk(struct wpa_supplicant *wpa_s, return 0; } +static inline void +wpas_p2p_update_dfs_ap_info_list(struct wpa_supplicant *wpa_s, + struct wpa_scan_results *scan_res) +{ +} #endif /* CONFIG_P2P */ #endif /* P2P_SUPPLICANT_H */ diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index 610072e..e153530 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1606,6 +1606,7 @@ struct wpa_supplicant { bool last_scan_all_chan; bool last_scan_non_coloc_6ghz; bool support_6ghz; + u8 assisted_dfs_go; struct wpa_signal_info last_signal_info; -- 2.7.4 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap