[PATCH v3 25/25] P2P: Add support for Assited DFS for P2P2 GO in 5GHz
Shivani Baranwal
quic_shivbara at quicinc.com
Mon Aug 5 02:33:23 PDT 2024
Signed-off-by: Shivani Baranwal <quic_shivbara at quicinc.com>
---
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
More information about the Hostap
mailing list