diff mbox series

[v2,04/14] P2P: Allow to process Element container attr from NAN SDFs

Message ID 1721364006-21658-5-git-send-email-quic_shivbara@quicinc.com
State Deferred
Headers show
Series Add support for P2P2 | expand

Commit Message

Shivani Baranwal July 19, 2024, 4:39 a.m. UTC
Extend support to process element container attribute from NAN SDF frames
and check if P2P attributes are present. Add P2P device entry if the NAN SDF
frames has matching service and P2P capabilities.

Signed-off-by: Shivani Baranwal <quic_shivbara@quicinc.com>
---
 src/common/ieee802_11_common.c    |  5 +++
 src/common/ieee802_11_common.h    |  2 ++
 src/common/ieee802_11_defs.h      |  2 ++
 src/common/nan_de.c               | 37 ++++++++++++++++++++++
 src/common/nan_de.h               |  4 +++
 src/p2p/p2p.c                     | 66 +++++++++++++++++++++++++++++++++++++++
 src/p2p/p2p.h                     | 16 +++++++++-
 src/p2p/p2p_i.h                   |  9 ++++++
 src/p2p/p2p_parse.c               | 34 ++++++++++++++++++++
 src/p2p/p2p_pd.c                  | 37 ++++++++++++++++++++++
 wpa_supplicant/nan_usd.c          | 10 ++++++
 wpa_supplicant/p2p_supplicant.c   | 11 +++++++
 wpa_supplicant/wpa_supplicant_i.h |  3 ++
 13 files changed, 235 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index ba1cb52..c753d49e 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -140,6 +140,11 @@  static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
 			elems->sae_pk = pos + 4;
 			elems->sae_pk_len = elen - 4;
 			break;
+		case P2P_2_OUI_TYPE:
+			/* Wi-Fi Alliance - P2P_2 IE */
+			elems->p2p2_ie = pos;
+			elems->p2p2_ie_len = elen;
+			break;
 		default:
 			wpa_printf(MSG_MSGDUMP, "Unknown WFA "
 				   "information element ignored "
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 9e9684c..32c6b08 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -65,6 +65,7 @@  struct ieee802_11_elems {
 	const u8 *vendor_ht_cap;
 	const u8 *vendor_vht;
 	const u8 *p2p;
+	const u8 *p2p2_ie;
 	const u8 *wfd;
 	const u8 *link_id;
 	const u8 *interworking;
@@ -136,6 +137,7 @@  struct ieee802_11_elems {
 	u8 vendor_ht_cap_len;
 	u8 vendor_vht_len;
 	u8 p2p_len;
+	u8 p2p2_ie_len;
 	u8 wfd_len;
 	u8 interworking_len;
 	u8 qos_map_set_len;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 578ea73..0549535 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -1711,6 +1711,8 @@  enum mbo_transition_reject_reason {
 /* Wi-Fi Direct (P2P) */
 
 #define P2P_OUI_TYPE 9
+#define P2P_2_OUI_TYPE 0x28
+
 
 enum p2p_attr_id {
 	P2P_ATTR_STATUS = 0,
diff --git a/src/common/nan_de.c b/src/common/nan_de.c
index 938a357..b1f798c 100644
--- a/src/common/nan_de.c
+++ b/src/common/nan_de.c
@@ -778,6 +778,33 @@  static void nan_de_get_sdea(const u8 *buf, size_t len, u8 instance_id,
 }
 
 
+void nan_de_process_elem_container(struct nan_de *de, const u8 *buf, size_t len,
+				   const u8 *peer_addr, unsigned int freq,
+				   bool p2p)
+{
+	const u8 *elem;
+	u16 elem_len;
+
+	elem = nan_de_get_attr(buf, len, NAN_ATTR_ELEM_CONTAINER, 0);
+	if (!elem)
+		return;
+
+	elem++;
+	elem_len = WPA_GET_LE16(elem);
+	elem += 2;
+	if (elem_len < 1 + 2)
+		return;
+
+	/* Skip Map ID */
+	elem++;
+	elem_len--;
+
+	if (p2p && de->cb.process_p2p_usd_elems)
+		de->cb.process_p2p_usd_elems(de->cb.ctx, elem, elem_len,
+					     peer_addr, freq);
+}
+
+
 static void nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv,
 			      const u8 *peer_addr, u8 instance_id,
 			      u8 req_instance_id, u16 sdea_control,
@@ -791,6 +818,9 @@  static void nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv,
 		nan_de_run_timer(de);
 	}
 
+	if (de->offload)
+		goto offload;
+
 	if (srv->subscribe.active && req_instance_id == 0) {
 		/* Active subscriber replies with a Subscribe message if it
 		 * received a matching unsolicited Publish message. */
@@ -805,6 +835,7 @@  static void nan_de_rx_publish(struct nan_de *de, struct nan_de_service *srv,
 				instance_id);
 	}
 
+offload:
 	if (de->cb.discovery_result)
 		de->cb.discovery_result(
 			de->cb.ctx, srv->id, srv_proto_type,
@@ -877,6 +908,9 @@  static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv,
 		return;
 	}
 
+	if (de->offload)
+		goto offload;
+
 	/* Reply with a solicited Publish message */
 	/* Service Descriptor attribute */
 	sda_len = NAN_SERVICE_ID_LEN + 1 + 1 + 1;
@@ -943,6 +977,7 @@  static void nan_de_rx_subscribe(struct nan_de *de, struct nan_de_service *srv,
 
 	nan_de_pause_state(srv, peer_addr, instance_id);
 
+offload:
 	if (!srv->publish.disable_events && de->cb.replied)
 		de->cb.replied(de->cb.ctx, srv->id, peer_addr, instance_id,
 			       srv_proto_type, ssi, ssi_len);
@@ -1098,6 +1133,8 @@  static void nan_de_rx_sda(struct nan_de *de, const u8 *peer_addr,
 				wpa_hexdump(MSG_MSGDUMP, "NAN: ssi",
 					    ssi, ssi_len);
 			}
+			nan_de_process_elem_container(de, buf, len, peer_addr,
+						      freq, srv->is_p2p);
 		}
 
 		switch (type) {
diff --git a/src/common/nan_de.h b/src/common/nan_de.h
index 73f6c9c..f369a57 100644
--- a/src/common/nan_de.h
+++ b/src/common/nan_de.h
@@ -53,6 +53,10 @@  struct nan_callbacks {
 	void (*receive)(void *ctx, int id, int peer_instance_id,
 			const u8 *ssi, size_t ssi_len,
 			const u8 *peer_addr);
+
+	void (*process_p2p_usd_elems)(void *ctx, const u8 *buf,
+				      u16 buf_len, const u8 *peer_addr,
+				      unsigned int freq);
 };
 
 struct nan_de * nan_de_init(const u8 *nmi, bool offload, bool ap,
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index a2d0962..aa6e8ed 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -5775,3 +5775,69 @@  struct wpabuf * p2p_usd_elems(struct p2p_data *p2p)
 
 	return buf;
 }
+
+void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len,
+			   const u8 *peer_addr, unsigned int freq)
+{
+	struct p2p_device *dev;
+	struct p2p_message msg;
+	const u8 *p2p_dev_addr;
+
+	os_memset(&msg, 0, sizeof(msg));
+	if (p2p_parse_ies(ies, ies_len, &msg)) {
+		p2p_dbg(p2p, "Failed to parse P2P IE for a device entry");
+		p2p_parse_free(&msg);
+		return;
+	}
+	if (msg.p2p_device_addr)
+		p2p_dev_addr = msg.p2p_device_addr;
+	else
+		p2p_dev_addr = peer_addr;
+
+	dev = p2p_create_device(p2p, p2p_dev_addr);
+	if (!dev) {
+		p2p_parse_free(&msg);
+		p2p_dbg(p2p, "P2P Device Add failure");
+		return;
+	}
+
+	/* Reset info from old IEs */
+	dev->info.reg_info = 0;
+	memset(&dev->info.pairing_config, 0, sizeof(struct p2p_pairing_config));
+
+	os_get_reltime(&dev->last_seen);
+	dev->listen_freq = freq;
+	dev->oper_freq = freq;
+
+	if (msg.capability) {
+		/*
+		 * P2P Client Discoverability bit is reserved in all frames
+		 * that use this function, so do not change its value here.
+		 */
+		dev->info.dev_capab &= P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
+		dev->info.dev_capab |= msg.capability[0] &
+			~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY;
+		dev->info.group_capab = msg.capability[1];
+	}
+
+	if (msg.pcea_info && msg.pcea_info_len >= 2)
+		p2p_process_pcea(p2p, &msg, dev);
+
+	if (msg.pbma_info && msg.pbma_info_len == 2)
+		dev->info.pairing_config.bootstrap_methods =
+						WPA_GET_LE16(msg.pbma_info);
+
+	if (!ether_addr_equal(peer_addr, p2p_dev_addr))
+		os_memcpy(dev->interface_addr, peer_addr, ETH_ALEN);
+
+	p2p_dbg(p2p, "Updated device entry based on USD frame: " MACSTR
+		" dev_capab=0x%x group_capab=0x%x listen_freq=%d",
+		MAC2STR(dev->info.p2p_device_addr), dev->info.dev_capab,
+		dev->info.group_capab, dev->listen_freq);
+
+	p2p->cfg->dev_found(p2p->cfg->cb_ctx,
+			    dev->info.p2p_device_addr,
+			    &dev->info, !(dev->flags & P2P_DEV_REPORTED_ONCE));
+
+	p2p_parse_free(&msg);
+}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index d8a5249..8e46506 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -447,6 +447,19 @@  struct p2p_peer_info {
 	 * p2ps_instance - P2PS Application Service Info
 	 */
 	struct wpabuf *p2ps_instance;
+
+	/* capability info in PCEA attribute */
+	u16 pcea_cap_info;
+
+	/**
+	 * The regulatory info encoding for operation in 6 GHz band
+	 */
+	u8 reg_info;
+
+	/**
+	 * p2p_pairing_config - P2P Pairing configuration
+	 */
+	struct p2p_pairing_config pairing_config;
 };
 
 enum p2p_prov_disc_status {
@@ -2486,5 +2499,6 @@  void set_p2p_allow_6ghz(struct p2p_data *p2p, bool value);
 int p2p_remove_6ghz_channels(struct weighted_pcl *pref_freq_list, int size);
 int p2p_channel_to_freq(int op_class, int channel);
 struct wpabuf * p2p_usd_elems(struct p2p_data *p2p);
-
+void p2p_process_usd_elems(struct p2p_data *p2p, const u8 *ies, u16 ies_len,
+			   const u8 *peer_addr, unsigned int freq);
 #endif /* P2P_H */
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 0e24e51..787e599 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -606,6 +606,7 @@  struct p2p_data {
  */
 struct p2p_message {
 	struct wpabuf *p2p_attributes;
+	struct wpabuf *p2p2_attributes;
 	struct wpabuf *wps_attributes;
 	struct wpabuf *wfd_subelems;
 
@@ -704,6 +705,12 @@  struct p2p_message {
 
 	const u8 *pref_freq_list;
 	size_t pref_freq_list_len;
+
+	const u8 *pcea_info;
+	size_t pcea_info_len;
+
+	const u8 *pbma_info;
+	size_t pbma_info_len;
 };
 
 
@@ -885,6 +892,8 @@  int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
 			   int join, int force_freq);
 void p2p_reset_pending_pd(struct p2p_data *p2p);
 void p2ps_prov_free(struct p2p_data *p2p);
+void p2p_process_pcea(struct p2p_data *p2p, struct p2p_message *msg,
+		      struct p2p_device *dev);
 
 /* p2p_invitation.c */
 void p2p_process_invitation_req(struct p2p_data *p2p, const u8 *sa,
diff --git a/src/p2p/p2p_parse.c b/src/p2p/p2p_parse.c
index 07d6ca0..a70e180 100644
--- a/src/p2p/p2p_parse.c
+++ b/src/p2p/p2p_parse.c
@@ -417,6 +417,26 @@  static int p2p_parse_attribute(u8 id, const u8 *data, u16 len,
 					msg->persistent_ssid_len));
 		break;
 	}
+	case P2P_ATTR_CAPABILITY_EXTENSION:
+		if (len < 2) {
+			wpa_printf(MSG_DEBUG, "P2P: Too short PCEA (length %d)",
+				   len);
+			return -1;
+		}
+		msg->pcea_info = data;
+		msg->pcea_info_len = len;
+		wpa_printf(MSG_DEBUG, "P2P: * PCEA (length=%u)", len);
+		break;
+	case P2P_ATTR_PAIRING_AND_BOOTSTRAPPING:
+		if (len < 1) {
+			wpa_printf(MSG_DEBUG, "P2P: Too short PBMA (length %d)",
+				   len);
+			return -1;
+		}
+		msg->pbma_info = data;
+		msg->pbma_info_len = len;
+		wpa_printf(MSG_DEBUG, "P2P: * PBMA (length=%u)", len);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "P2P: Skipped unknown attribute %d "
 			   "(length %d)", id, len);
@@ -573,6 +593,18 @@  int p2p_parse_ies(const u8 *data, size_t len, struct p2p_message *msg)
 		return -1;
 	}
 
+	msg->p2p2_attributes = ieee802_11_vendor_ie_concat(data, len,
+							   P2P2_IE_VENDOR_TYPE);
+	if (msg->p2p2_attributes &&
+	    p2p_parse_p2p_ie(msg->p2p2_attributes, msg)) {
+		wpa_printf(MSG_DEBUG, "P2P: Failed to parse P2P2 IE data");
+		if (msg->p2p2_attributes)
+			wpa_hexdump_buf(MSG_MSGDUMP, "P2P: P2P2 IE data",
+					msg->p2p2_attributes);
+		p2p_parse_free(msg);
+		return -1;
+	}
+
 #ifdef CONFIG_WIFI_DISPLAY
 	if (elems.wfd) {
 		msg->wfd_subelems = ieee802_11_vendor_ie_concat(
@@ -647,6 +679,8 @@  void p2p_parse_free(struct p2p_message *msg)
 {
 	wpabuf_free(msg->p2p_attributes);
 	msg->p2p_attributes = NULL;
+	wpabuf_free(msg->p2p2_attributes);
+	msg->p2p2_attributes = NULL;
 	wpabuf_free(msg->wps_attributes);
 	msg->wps_attributes = NULL;
 #ifdef CONFIG_WIFI_DISPLAY
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 542521e..7f9ee08 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -562,6 +562,43 @@  do { \
 	return 0;
 }
 
+void p2p_process_pcea(struct p2p_data *p2p, struct p2p_message *msg,
+		      struct p2p_device *dev)
+{
+	const u8 *pos;
+	u8 cap_info_len;
+
+	if (!p2p || !dev || !msg || !msg->pcea_info)
+		return;
+
+	pos = msg->pcea_info;
+	dev->info.pcea_cap_info = WPA_GET_LE16(pos);
+	cap_info_len = dev->info.pcea_cap_info & P2P_PCEA_LEN_MASK;
+
+	/* Field length is (n-1), n in octets */
+	pos += cap_info_len + 1;
+
+	if (dev->info.pcea_cap_info & P2P_PCEA_6GHZ) {
+		dev->support_6ghz = true;
+	}
+	if (dev->info.pcea_cap_info & P2P_PCEA_REG_INFO)
+		dev->info.reg_info = *pos++;
+
+	if (dev->info.pcea_cap_info & P2P_PCEA_PASN_TYPE)
+		dev->info.pairing_config.pasn_type = *pos++;
+
+	if (dev->info.pcea_cap_info & P2P_PCEA_PAIRING_CAPABLE)
+		dev->info.pairing_config.pairing_capable = 1;
+
+	if (dev->info.pcea_cap_info & P2P_PCEA_PAIRING_SETUP_ENABLE)
+		dev->info.pairing_config.enable_pairing_setup = 1;
+
+	if (dev->info.pcea_cap_info & P2P_PCEA_PMK_CACHING) {
+		dev->info.pairing_config.enable_pairing_cache = 1;
+		dev->info.pairing_config.enable_pairing_verification = 1;
+	}
+}
+
 
 void p2p_process_prov_disc_req(struct p2p_data *p2p, const u8 *sa,
 			       const u8 *data, size_t len, int rx_freq)
diff --git a/wpa_supplicant/nan_usd.c b/wpa_supplicant/nan_usd.c
index 0b32949..362832c 100644
--- a/wpa_supplicant/nan_usd.c
+++ b/wpa_supplicant/nan_usd.c
@@ -335,6 +335,15 @@  static void wpas_nan_de_receive(void *ctx, int id, int peer_instance_id,
 	os_free(ssi_hex);
 }
 
+static void wpas_nan_process_p2p_usd_elems(void *ctx, const u8 *buf,
+					   u16 buf_len, const u8 *peer_addr,
+					   unsigned int freq)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	wpas_p2p_process_usd_elems(wpa_s, buf, buf_len, peer_addr, freq);
+}
+
 
 int wpas_nan_usd_init(struct wpa_supplicant *wpa_s)
 {
@@ -350,6 +359,7 @@  int wpas_nan_usd_init(struct wpa_supplicant *wpa_s)
 	cb.publish_terminated = wpas_nan_de_publish_terminated;
 	cb.subscribe_terminated = wpas_nan_de_subscribe_terminated;
 	cb.receive = wpas_nan_de_receive;
+	cb.process_p2p_usd_elems = wpas_nan_process_p2p_usd_elems;
 
 	wpa_s->nan_de = nan_de_init(wpa_s->own_addr, offload, false, &cb);
 	if (!wpa_s->nan_de)
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 2df2d10..b31e910 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -10252,3 +10252,14 @@  struct wpabuf * wpas_p2p_usd_elems(struct wpa_supplicant *wpa_s)
 		return NULL;
 	return p2p_usd_elems(p2p);
 }
+
+void wpas_p2p_process_usd_elems(struct wpa_supplicant *wpa_s, const u8 *buf,
+				u16 buf_len, const u8 *peer_addr,
+				unsigned int freq)
+{
+	struct p2p_data *p2p = wpa_s->global->p2p;
+
+	if (wpa_s->global->p2p_disabled || !p2p)
+		return;
+	p2p_process_usd_elems(p2p, buf, buf_len, peer_addr, freq);
+}
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 110a864..57082ab 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -2010,5 +2010,8 @@  bool wpas_is_6ghz_supported(struct wpa_supplicant *wpa_s, bool only_enabled);
 
 bool wpa_is_non_eht_scs_traffic_desc_supported(struct wpa_bss *bss);
 bool wpas_ap_link_address(struct wpa_supplicant *wpa_s, const u8 *addr);
+void wpas_p2p_process_usd_elems(struct wpa_supplicant *wpa_s, const u8 *buf,
+				u16 buf_len, const u8 *peer_addr,
+				unsigned int freq);
 
 #endif /* WPA_SUPPLICANT_I_H */