]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
PR: Attribute parsing for Proximity Ranging element
authorPeddolla Harshavardhan Reddy <peddolla@qti.qualcomm.com>
Sat, 26 Apr 2025 19:43:05 +0000 (01:13 +0530)
committerJouni Malinen <j@w1.fi>
Fri, 17 Oct 2025 10:22:51 +0000 (13:22 +0300)
Add functionality to locate the Proximity Ranging element, and parse the
attributes from this element. This element contains ranging
capabilities, device identity resolution attribute, and such. This is
also stored in a message structure to be processed further.

Signed-off-by: Peddolla Harshavardhan Reddy <peddolla@qti.qualcomm.com>
src/common/proximity_ranging.c
src/common/proximity_ranging.h

index 41144cb28fb04a9cee80467a3286c599d520232f..f0b3f90f8485ffc157111ece8020ef3b50219406 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
 #include "crypto/sha256.h"
 #include "proximity_ranging.h"
 
@@ -537,17 +538,207 @@ struct wpabuf * pr_prepare_usd_elems(struct pr_data *pr)
 }
 
 
+static int pr_parse_attribute(u8 id, const u8 *data, u16 len,
+                             struct pr_message *msg)
+{
+       switch (id) {
+       case PR_ATTR_STATUS:
+               if (len < 1) {
+                       wpa_printf(MSG_INFO,
+                                  "PR: Invalid Proximity Ranging Status Attribute (length %d)",
+                                  len);
+                       return -1;
+               }
+               msg->status_ie = data;
+               msg->status_ie_len = len;
+               wpa_printf(MSG_DEBUG, "PR: Status Code %u", data[0]);
+               break;
+       case PR_ATTR_RANGING_CAPABILITY:
+               if (len < 35) {
+                       wpa_printf(MSG_INFO,
+                                  "PR: Too short Proximity Ranging Capability Attribute (length %d)",
+                                  len);
+                       return -1;
+               }
+               msg->pr_capability = data;
+               msg->pr_capability_len = len;
+               wpa_printf(MSG_DEBUG,
+                          "PR: Ranging Protocol Type: %02x PASN Type: %02x",
+                          data[0], data[1]);
+               break;
+       case PR_ATTR_EDCA_CAPABILITY:
+               if (len < 10) {
+                       wpa_printf(MSG_INFO,
+                                  "PR: Too short Proximity Ranging EDCA Capability Attribute (length %d)",
+                                  len);
+                       return -1;
+               }
+               msg->edca_capability = data;
+               msg->edca_capability_len = len;
+               wpa_printf(MSG_DEBUG,
+                          "PR: EDCA Ranging Role %02x, Ranging Parameters %04x",
+                          data[0], WPA_GET_LE16(data + 1));
+               break;
+       case PR_ATTR_NTB_CAPABILITY:
+               if (len < 12) {
+                       wpa_printf(MSG_INFO,
+                                  "PR: Too short Proximity Ranging 11az NTB Capability Attribute (length %d)",
+                                  len);
+                       return -1;
+               }
+               msg->ntb_capability = data;
+               msg->ntb_capability_len = len;
+               wpa_printf(MSG_DEBUG,
+                          "PR: NTB Ranging Role %02x, Ranging Parameter %04x",
+                          data[0], WPA_GET_LE32(data + 1));
+               break;
+       case PR_ATTR_OPERATION_MODE:
+               if (len < 9) {
+                       wpa_printf(MSG_INFO,
+                                  "PR: Invalid Proximity Ranging Operation Mode Attribute (length %d)",
+                                  len);
+                       return -1;
+               }
+               msg->op_mode = data;
+               msg->op_mode_len = len;
+               break;
+       case PR_ATTR_DEVICE_IDENTITY_RESOLUTION:
+               if (len < 1 + DEVICE_IDENTITY_NONCE_LEN +
+                   DEVICE_IDENTITY_TAG_LEN) {
+                       wpa_printf(MSG_INFO, "PR: Too short DIRA (length %d)",
+                                  len);
+                       return -1;
+               }
+               msg->dira = data;
+               msg->dira_len = len;
+               wpa_printf(MSG_DEBUG, "PR: DIRA cipher version %u", data[0]);
+               break;
+       default:
+               wpa_printf(MSG_DEBUG,
+                          "PR: Skipped unknown attribute %d (length %d)",
+                          id, len);
+               break;
+       }
+
+       return 0;
+}
+
+
+/**
+ * pr_parse_proximity_ranging_element - Parse Proximity Ranging element
+ * @buf: Concatenated PR element(s) payload
+ * @msg: Buffer for returning parsed attributes
+ * Returns: 0 on success, -1 on failure
+ *
+ * Note: The caller is responsible for clearing the msg data structure before
+ * calling this function.
+ */
+static int pr_parse_proximity_ranging_element(const struct wpabuf *buf,
+                                             struct pr_message *msg)
+{
+       const u8 *pos = wpabuf_head_u8(buf);
+       const u8 *end = pos + wpabuf_len(buf);
+
+       wpa_printf(MSG_DEBUG, "PR: Parsing Proximity Ranging element");
+
+       while (pos < end) {
+               u16 attr_len;
+               u8 id;
+
+               if (end - pos < 3) {
+                       wpa_printf(MSG_DEBUG, "PR: Invalid PR attribute");
+                       return -1;
+               }
+               id = *pos++;
+               attr_len = WPA_GET_LE16(pos);
+               pos += 2;
+               wpa_printf(MSG_DEBUG, "PR: Attribute %d length %u",
+                          id, attr_len);
+               if (attr_len > end - pos) {
+                       wpa_printf(MSG_DEBUG,
+                                  "PR: Attribute underflow (len=%u left=%d)",
+                                  attr_len, (int) (end - pos));
+                       wpa_hexdump(MSG_MSGDUMP, "PR: Data", pos, end - pos);
+                       return -1;
+               }
+               if (pr_parse_attribute(id, pos, attr_len, msg))
+                       return -1;
+               pos += attr_len;
+       }
+
+       return 0;
+}
+
+
+static void pr_parse_free(struct pr_message *msg)
+{
+       wpabuf_free(msg->pr_attributes);
+       msg->pr_attributes = NULL;
+}
+
+
+/**
+ * pr_parse_elements - Parse Proximity Ranging element(s)
+ * @data: Elements from the message
+ * @len: Length of data buffer in octets
+ * @msg: Buffer for returning parsed attributes
+ * Returns: 0 on success, -1 on failure
+ *
+ * Note: The caller is responsible for clearing the msg data structure before
+ * calling this function.
+ *
+ * Note: The caller must free temporary memory allocations by calling
+ * pr_parse_free() when the parsed data is not needed anymore.
+ */
+static int pr_parse_elements(const u8 *data, size_t len, struct pr_message *msg)
+{
+       struct ieee802_11_elems elems;
+
+       if (ieee802_11_parse_elems(data, len, &elems, true) == ParseFailed)
+               return -1;
+
+       msg->pr_attributes = ieee802_11_vendor_ie_concat(data, len,
+                                                        PR_IE_VENDOR_TYPE);
+       if (msg->pr_attributes &&
+           pr_parse_proximity_ranging_element(msg->pr_attributes, msg)) {
+               wpa_printf(MSG_INFO,
+                          "PR: Failed to parse Proximity Ranging element data");
+               if (msg->pr_attributes)
+                       wpa_hexdump_buf(MSG_MSGDUMP,
+                                       "PR: Proximity Ranging element payload",
+                                       msg->pr_attributes);
+               pr_parse_free(msg);
+               return -1;
+       }
+       return 0;
+}
+
+
 void pr_process_usd_elems(struct pr_data *pr, const u8 *ies, u16 ies_len,
                          const u8 *peer_addr, unsigned int freq)
 {
        struct pr_device *dev;
+       struct pr_message msg;
+
+       os_memset(&msg, 0, sizeof(msg));
+       os_memcpy(msg.pr_device_addr, peer_addr, ETH_ALEN);
+
+       if (pr_parse_elements(ies, ies_len, &msg)) {
+               wpa_printf(MSG_INFO,
+                          "PR: Failed to parse Proximity Ranging element(s)");
+               pr_parse_free(&msg);
+               return;
+       }
 
        dev = pr_create_device(pr, peer_addr);
        if (!dev) {
+               pr_parse_free(&msg);
                wpa_printf(MSG_INFO, "PR: Failed to create a device");
                return;
        }
 
        os_get_reltime(&dev->last_seen);
        dev->listen_freq = freq;
+
+       pr_parse_free(&msg);
 }
index 6734e9c40a6b0cc705e39578ea7370f35698977e..2737dea30ceec16235e4047c381d741a2274cb83 100644 (file)
@@ -262,6 +262,34 @@ struct pr_device {
 };
 
 
+/**
+ * struct pr_message - Proximity ranging peer information
+ */
+struct pr_message {
+       struct wpabuf *pr_attributes;
+
+       u8 pr_device_addr[ETH_ALEN];
+
+       const u8 *pr_capability;
+       size_t pr_capability_len;
+
+       const u8 *edca_capability;
+       size_t edca_capability_len;
+
+       const u8 *ntb_capability;
+       size_t ntb_capability_len;
+
+       const u8 *dira;
+       size_t dira_len;
+
+       const u8 *status_ie;
+       size_t status_ie_len;
+
+       const u8 *op_mode;
+       size_t op_mode_len;
+};
+
+
 struct pr_config {
        u8 pasn_type;