]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
PR: Determine channels that are supported to perform ranging
authorPeddolla Harshavardhan Reddy <peddolla@qti.qualcomm.com>
Tue, 19 Aug 2025 12:31:16 +0000 (18:01 +0530)
committerJouni Malinen <j@w1.fi>
Fri, 17 Oct 2025 10:21:43 +0000 (13:21 +0300)
Fetch supported channels for ranging and store them in Proximity Ranging
global context. This includes channels where Enhanced Distributed
channel Access (EDCA-802.11mc) is supported as well channels where
Non-Trigger Based (NTB-802.11az) ranging is supported based on the
corresponding format and bandwidth.

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

index 6be3c4401e81f142314587d5768dabcba16dae63..f26952fc2f9f42eed6f25f24bf7f1b5ca7260725 100644 (file)
 
 #include "utils/list.h"
 
+/**
+ * PR_MAX_OP_CLASSES - Maximum number of operating classes
+ */
+#define PR_MAX_OP_CLASSES 15
+
+/**
+ * PR_MAX_OP_CLASS_CHANNELS - Maximum number of channels per operating class
+ */
+#define PR_MAX_OP_CLASS_CHANNELS 60
+
 /**
  * PR_MAX_PEER - Maximum number of Proximity Ranging peers that device can store
  */
 #define PR_MAX_PEER 100
 
+/**
+ * struct pr_channels - List of supported channels
+ */
+struct pr_channels {
+       /**
+        * struct pr_op_class - Supported operating class
+        */
+       struct pr_op_class {
+               /**
+                * op_class - Operating class
+                */
+               u8 op_class;
+
+               /**
+                * channel - Supported channels
+                */
+               u8 channel[PR_MAX_OP_CLASS_CHANNELS];
+
+               /**
+                * channels - Number of channel entries in use
+                */
+               size_t channels;
+       } op_class[PR_MAX_OP_CLASSES];
+
+       /**
+        * op_classes - Number of op_class entries in use
+        */
+       size_t op_classes;
+};
+
+/**
+ * Format and Bandwidth values for EDCA based ranging with range of 10-16
+ * from IEEE Std 802.11-2024, 9.4.2.166 (FTM Parameters element), Table 9-325
+ * (Format And Bandwidth subfield) as specified in Proximity Ranging
+ * Implementation Considerations for P2P Operation, Draft 1.8, Table 8
+ * (Proximity Ranging EDCA Capability Attribute format) for the the Ranging
+ * Parameters field B0-B3.
+ */
+enum edca_format_and_bw_value {
+       EDCA_FORMAT_AND_BW_VHT20 = 10,
+       EDCA_FORMAT_AND_BW_HT40 = 11,
+       EDCA_FORMAT_AND_BW_VHT40 = 12,
+       EDCA_FORMAT_AND_BW_VHT80 = 13,
+       EDCA_FORMAT_AND_BW_VHT80P80 = 14,
+       EDCA_FORMAT_AND_BW_VHT160_DUAL_LO = 15,
+       EDCA_FORMAT_AND_BW_VHT160_SINGLE_LO = 16,
+};
+
+/**
+ * Format and Bandwidth values for NTB based ranging as from IEEE Std
+ * 802.11-2024, 9.4.2.300 (Ranging Parameters element), Table 9-412 (Format And
+ * Bandwidth subfield) as specified in Proximity Ranging Implementation
+ * Considerations for P2P Operation, Draft 1.8, Table 9 (Proximity Ranging 11az
+ * NTB Capability Attribute format) for the Ranging Parameter field B0-B2.
+ */
+enum ntb_format_and_bw_value {
+       NTB_FORMAT_AND_BW_HE20 = 0,
+       NTB_FORMAT_AND_BW_HE40 = 1,
+       NTB_FORMAT_AND_BW_HE80 = 2,
+       NTB_FORMAT_AND_BW_HE80P80 = 3,
+       NTB_FORMAT_AND_BW_HE160_DUAL_LO = 4,
+       NTB_FORMAT_AND_BW_HE160_SINGLE_LO = 5,
+};
+
 /**
  * struct pr_device_info - Proximity ranging peer information
  */
@@ -54,6 +128,8 @@ struct pr_config {
 
        u8 max_rx_antenna;
 
+       struct pr_channels edca_channels;
+
        bool ntb_ista_support;
 
        bool ntb_rsta_support;
@@ -78,6 +154,8 @@ struct pr_config {
 
        u8 ntb_format_and_bw;
 
+       struct pr_channels ntb_channels;
+
        bool support_6ghz;
 
        /**
index f0b00cd04233c90f70e085a0dc54af4549c15a69..c8ce63a42da4a6233e84aa5bb70b1a8aef314807 100644 (file)
 #include "pr_supplicant.h"
 
 
+static int wpas_pr_edca_get_bw(enum edca_format_and_bw_value format_and_bw)
+{
+       switch (format_and_bw) {
+       case EDCA_FORMAT_AND_BW_VHT20:
+               return 20;
+       case EDCA_FORMAT_AND_BW_HT40:
+       case EDCA_FORMAT_AND_BW_VHT40:
+               return 40;
+       case EDCA_FORMAT_AND_BW_VHT80:
+               return 80;
+       case EDCA_FORMAT_AND_BW_VHT80P80:
+       case EDCA_FORMAT_AND_BW_VHT160_DUAL_LO:
+       case EDCA_FORMAT_AND_BW_VHT160_SINGLE_LO:
+               return 160;
+       default:
+               return 0;
+       }
+}
+
+
+static int wpas_pr_ntb_get_bw(enum ntb_format_and_bw_value format_and_bw)
+{
+       switch (format_and_bw) {
+       case NTB_FORMAT_AND_BW_HE20:
+               return 20;
+       case NTB_FORMAT_AND_BW_HE40:
+               return 40;
+       case NTB_FORMAT_AND_BW_HE80:
+               return 80;
+       case NTB_FORMAT_AND_BW_HE80P80:
+       case NTB_FORMAT_AND_BW_HE160_DUAL_LO:
+       case NTB_FORMAT_AND_BW_HE160_SINGLE_LO:
+               return 160;
+       default:
+               return 0;
+       }
+}
+
+
+static bool
+wpas_pr_edca_is_valid_op_class(enum edca_format_and_bw_value format_and_bw,
+                              const struct oper_class_map *op_class_map)
+{
+       int bw = 0, op_class_bw = 0;
+
+       if (!op_class_map)
+               return false;
+
+       op_class_bw = oper_class_bw_to_int(op_class_map);
+       bw = wpas_pr_edca_get_bw(format_and_bw);
+
+       if (!op_class_bw || !bw)
+               return false;
+
+       if (format_and_bw <= EDCA_FORMAT_AND_BW_VHT80 &&
+           format_and_bw >= EDCA_FORMAT_AND_BW_VHT20 &&
+           op_class_bw <= bw)
+               return true;
+
+       if (format_and_bw == EDCA_FORMAT_AND_BW_VHT80P80 &&
+           (op_class_bw < bw || op_class_map->bw == BW80P80))
+               return true;
+
+       if ((format_and_bw == EDCA_FORMAT_AND_BW_VHT160_DUAL_LO ||
+            format_and_bw == EDCA_FORMAT_AND_BW_VHT160_SINGLE_LO) &&
+           (op_class_bw < bw || op_class_map->bw == BW160))
+               return true;
+
+       return false;
+}
+
+
+static bool
+wpas_pr_ntb_is_valid_op_class(enum ntb_format_and_bw_value format_and_bw,
+                             const struct oper_class_map *op_class_map)
+{
+       int bw = 0, op_class_bw = 0;
+
+       if (!op_class_map)
+               return false;
+
+       op_class_bw = oper_class_bw_to_int(op_class_map);
+       bw = wpas_pr_ntb_get_bw(format_and_bw);
+
+       if (!op_class_bw || !bw)
+               return false;
+
+       if (format_and_bw <= NTB_FORMAT_AND_BW_HE80 &&
+           format_and_bw >= NTB_FORMAT_AND_BW_HE20 &&
+           op_class_bw <= bw)
+               return true;
+
+       if (format_and_bw == NTB_FORMAT_AND_BW_HE80P80 &&
+                  (op_class_bw < bw || op_class_map->bw == BW80P80))
+               return true;
+
+       if ((format_and_bw == NTB_FORMAT_AND_BW_HE160_DUAL_LO ||
+            format_and_bw == NTB_FORMAT_AND_BW_HE160_SINGLE_LO) &&
+           (op_class_bw < bw || op_class_map->bw == BW160))
+               return true;
+
+       return false;
+}
+
+
+static void
+wpas_pr_setup_edca_channels(struct wpa_supplicant *wpa_s,
+                           struct pr_channels *chan,
+                           enum edca_format_and_bw_value format_and_bw)
+{
+       struct hostapd_hw_modes *mode;
+       int cla = 0, i;
+
+       for (i = 0; global_op_class[i].op_class; i++) {
+               unsigned int ch;
+               struct pr_op_class *op = NULL;
+               const struct oper_class_map *o = &global_op_class[i];
+
+               mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode,
+                               is_6ghz_op_class(o->op_class));
+               if (!mode || is_6ghz_op_class(o->op_class) ||
+                   !wpas_pr_edca_is_valid_op_class(format_and_bw, o))
+                       continue;
+
+               for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
+                       enum chan_allowed res;
+
+                       /* Check for non-continuous jump in channel index
+                        * increment.
+                        */
+                       if (o->op_class >= 128 && o->op_class <= 130 &&
+                           ch < 149 && ch + o->inc > 149)
+                               ch = 149;
+
+                       res = verify_channel(mode, o->op_class, ch, o->bw);
+
+                       if (res == ALLOWED) {
+                               if (!op) {
+                                       if (cla == PR_MAX_OP_CLASSES)
+                                               continue;
+
+                                       wpa_printf(MSG_DEBUG,
+                                                  "PR: Add operating class: %u (EDCA)",
+                                                  o->op_class);
+                                       op = &chan->op_class[cla];
+                                       cla++;
+                                       op->op_class = o->op_class;
+                               }
+                               if (op->channels == PR_MAX_OP_CLASS_CHANNELS)
+                                       continue;
+                               op->channel[op->channels] = ch;
+                               op->channels++;
+                       }
+               }
+
+               if (op)
+                       wpa_hexdump(MSG_DEBUG, "PR: Channels (EDCA)",
+                                   op->channel, op->channels);
+       }
+
+       chan->op_classes = cla;
+}
+
+
+static void
+wpas_pr_setup_ntb_channels(struct wpa_supplicant *wpa_s,
+                          struct pr_channels *chan,
+                          enum ntb_format_and_bw_value format_and_bw,
+                          bool allow_6ghz)
+{
+       int cla = 0, i;
+       struct hostapd_hw_modes *mode;
+
+       for (i = 0; global_op_class[i].op_class; i++) {
+               unsigned int ch;
+               struct pr_op_class *op = NULL;
+               const struct oper_class_map *o = &global_op_class[i];
+
+               mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode,
+                               is_6ghz_op_class(o->op_class));
+               if (!mode || (!allow_6ghz && is_6ghz_op_class(o->op_class)) ||
+                   !wpas_pr_ntb_is_valid_op_class(format_and_bw, o))
+                       continue;
+
+               for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
+                       enum chan_allowed res;
+
+                       /* Check for non-continuous jump in channel index
+                        * increment.
+                        */
+                       if (o->op_class >= 128 && o->op_class <= 130 &&
+                           ch < 149 && ch + o->inc > 149)
+                               ch = 149;
+
+                       res = verify_channel(mode, o->op_class, ch, o->bw);
+
+                       if (res == ALLOWED) {
+                               if (!op) {
+                                       if (cla == PR_MAX_OP_CLASSES)
+                                               continue;
+                                       wpa_printf(MSG_DEBUG,
+                                                  "PR: Add operating class: %u (NTB)",
+                                                  o->op_class);
+                                       op = &chan->op_class[cla];
+                                       cla++;
+                                       op->op_class = o->op_class;
+                               }
+                               if (op->channels == PR_MAX_OP_CLASS_CHANNELS)
+                                       continue;
+                               op->channel[op->channels] = ch;
+                               op->channels++;
+                       }
+               }
+               if (op) {
+                       wpa_hexdump(MSG_DEBUG, "PR: Channels (NTB)",
+                                   op->channel, op->channels);
+               }
+       }
+
+       chan->op_classes = cla;
+}
+
+
 int wpas_pr_init(struct wpa_global *global, struct wpa_supplicant *wpa_s,
                 const struct wpa_driver_capa *capa)
 {
@@ -39,6 +262,9 @@ int wpas_pr_init(struct wpa_global *global, struct wpa_supplicant *wpa_s,
        pr.max_rx_antenna = capa->max_rx_antenna;
        pr.max_tx_antenna = capa->max_tx_antenna;
 
+       wpas_pr_setup_edca_channels(wpa_s, &pr.edca_channels,
+                                   pr.edca_format_and_bw);
+
        pr.ntb_ista_support = wpa_s->drv_flags2 &
                WPA_DRIVER_FLAGS2_NON_TRIGGER_BASED_INITIATOR;
        pr.ntb_rsta_support = wpa_s->drv_flags2 &
@@ -57,6 +283,10 @@ int wpas_pr_init(struct wpa_global *global, struct wpa_supplicant *wpa_s,
 
        pr.secure_he_ltf = wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_SEC_LTF_STA;
 
+       wpas_pr_setup_ntb_channels(wpa_s, &pr.ntb_channels,
+                                  pr.ntb_format_and_bw,
+                                  pr.support_6ghz);
+
        if (wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
                os_memcpy(pr.country, wpa_s->conf->country, 2);
                pr.country[2] = 0x04;