@@ -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 "
@@ -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;
@@ -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,
@@ -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) {
@@ -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,
@@ -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);
+}
@@ -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 {
@@ -2491,5 +2504,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 */
@@ -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,
@@ -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
@@ -562,6 +562,40 @@ 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_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)
@@ -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)
@@ -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);
+}
@@ -2004,5 +2004,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 */
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>