iwinfo: export HE and EHT operation in scan results master
authorAleksander Jan Bajkowski <[email protected]>
Fri, 14 Mar 2025 19:22:30 +0000 (20:22 +0100)
committerRobert Marko <[email protected]>
Fri, 7 Nov 2025 11:21:23 +0000 (12:21 +0100)
Export WiFi 6E (HE) and WiFi 7 (EHT) operation data in scan results.
These additional data can be useful to check wifi channel utilization
by nearby stations.

Example
Cell 22 - Address: xx:xx:xx:xx:xx:xx
          ESSID: "OpenWrt"
          Mode: Master  Frequency: 5.955 GHz  Band: 6 GHz  Channel: 1
          Signal: -21 dBm  Quality: 70/70
          Encryption: WPA3 SAE (CCMP)
          HE Operation:
                    Center Frequency 1: 7
                    Center Frequency 2: 15
                    Channel Width: 160 MHz
          EHT Operation:
                    Center Frequency 1: 15
                    Center Frequency 2: 31
                    Channel Width: 320 MHz

Signed-off-by: Aleksander Jan Bajkowski <[email protected]>
Link: https://github.com/openwrt/iwinfo/pull/21
Signed-off-by: Robert Marko <[email protected]>
include/iwinfo.h
iwinfo_cli.c
iwinfo_lib.c
iwinfo_nl80211.c

index 2a841be12f93a4d7e3bb17547a9e7c230a4ee748..2625fbdcccd696e31bf5c1d05ee01955fdb1ea60 100644 (file)
@@ -330,6 +330,12 @@ extern const uint16_t ht_chan_width[2];
    2 = 160 MHz
    3 = 80+80 MHz */
 extern const uint16_t vht_chan_width[4];
+/* 0 = 20 MHz
+   1 = 40 MHz
+   2 = 80 MHz
+   3 = 80+80 or 160 MHz
+   4 = 160+160 or 320 MHz */
+extern const uint16_t eht_chan_width[5];
 
 struct iwinfo_scanlist_entry {
        uint8_t mac[6];
@@ -344,6 +350,8 @@ struct iwinfo_scanlist_entry {
        struct iwinfo_crypto_entry crypto;
        struct iwinfo_scanlist_ht_chan_entry ht_chan_info;
        struct iwinfo_scanlist_vht_chan_entry vht_chan_info;
+       struct iwinfo_scanlist_vht_chan_entry he_chan_info;
+       struct iwinfo_scanlist_vht_chan_entry eht_chan_info;
 };
 
 struct iwinfo_country_entry {
index 0966d1b535047d462dd0d9f16717260cd10718c4..84a9833d9776624d32676373edeb89fd7fea2df6 100644 (file)
@@ -362,6 +362,19 @@ static const char* format_chan_width(bool vht, uint8_t width)
        return "unknown";
 }
 
+static const char* format_6ghz_chan_width(uint8_t width)
+{
+       if (width < ARRAY_SIZE(eht_chan_width))
+               switch (eht_chan_width[width]) {
+                       case 20: return "20 MHz";
+                       case 40: return "40 MHz";
+                       case 80: return "80 MHz";
+                       case 160: return "160 MHz";
+                       case 320: return "320 MHz";
+               }
+
+       return "unknown";
+}
 
 static const char * print_type(const struct iwinfo_ops *iw, const char *ifname)
 {
@@ -720,6 +733,26 @@ static void print_scanlist(const struct iwinfo_ops *iw, const char *ifname)
                                format_chan_width(true, e->vht_chan_info.chan_width));
                }
 
+               if (e->he_chan_info.center_chan_1) {
+                       printf("          HE Operation:\n");
+                       printf("                    Center Frequency 1: %d\n",
+                                e->he_chan_info.center_chan_1);
+                       printf("                    Center Frequency 2: %d\n",
+                                e->he_chan_info.center_chan_2);
+                       printf("                    Channel Width: %s\n",
+                               format_6ghz_chan_width(e->he_chan_info.chan_width));
+               }
+
+               if (e->eht_chan_info.center_chan_1) {
+                       printf("          EHT Operation:\n");
+                       printf("                    Center Frequency 1: %d\n",
+                                e->eht_chan_info.center_chan_1);
+                       printf("                    Center Frequency 2: %d\n",
+                                e->eht_chan_info.center_chan_2);
+                       printf("                    Channel Width: %s\n",
+                               format_6ghz_chan_width(e->eht_chan_info.chan_width));
+               }
+
                printf("\n");
        }
 }
index f9f6569f2edba83712af8ccaa48f5069ecf57afc..7b1d5ef33e58d04ca56fc2ea410acadf71a11518 100644 (file)
@@ -133,6 +133,14 @@ const uint16_t vht_chan_width[4] = {
        8080, /* 80+80 MHz */
 };
 
+const uint16_t eht_chan_width[5] = {
+       20, /* 20 MHz */
+       40, /* 40 MHz */
+       80, /* 80 MHz */
+       160, /* 80+80 or 160 MHz */
+       320, /* 160+160 or 320 MHz */
+};
+
 /*
  * ISO3166 country labels
  */
index 97f2131ef8f24ff3452995a54cdb99aabfa7df77..cd801af0654f15c59e97600397e41bf0093d1de9 100644 (file)
@@ -2567,6 +2567,66 @@ struct nl80211_scanlist {
 };
 
 
+static void nl80211_get_scanlist_he_operation(unsigned char len,
+               unsigned char *ie, struct iwinfo_scanlist_entry *e)
+{
+       uint8_t offset = 6;
+
+       /* 6 GHz Operation Info not present */
+       if (!(ie[2] & 0x02))
+               return;
+
+       /* VHT Operation Info present */
+       if (ie[1] & 0x40)
+               offset += 3;
+
+       /* Co Hosted BSS present */
+       if (ie[1] & 0x80)
+               offset += 1;
+
+       if (len - offset < 5)
+               return;
+
+       e->he_chan_info.chan_width = ie[offset + 1] & 0x03;
+       e->he_chan_info.center_chan_1 = ie[offset + 2];
+       e->he_chan_info.center_chan_2 = ie[offset + 3];
+}
+
+
+static void nl80211_get_scanlist_eht_operation(unsigned char len,
+               unsigned char *ie, struct iwinfo_scanlist_entry *e)
+{
+       /* EHT Operation Info not present */
+       if (!(ie[0] & 0x01))
+               return;
+
+       if (len < 8)
+               return;
+
+       e->eht_chan_info.chan_width = ie[5] & 0x07;
+       e->eht_chan_info.center_chan_1 = ie[6];
+       e->eht_chan_info.center_chan_2 = ie[7];
+}
+
+
+static void nl80211_get_scanlist_extension(unsigned char len,
+               unsigned char *ie, struct iwinfo_scanlist_entry *e)
+{
+       if (len < 1)
+               return;
+
+       switch (ie[0])
+       {
+       case 36: /* HE Operation */
+               nl80211_get_scanlist_he_operation(len - 1, ie + 1, e);
+               break;
+       case 106: /* EHT Operation */
+               nl80211_get_scanlist_eht_operation(len - 1, ie + 1, e);
+               break;
+       }
+}
+
+
 static void nl80211_get_scanlist_ie(struct nlattr **bss,
                                     struct iwinfo_scanlist_entry *e)
 {
@@ -2612,6 +2672,9 @@ static void nl80211_get_scanlist_ie(struct nlattr **bss,
                                e->vht_chan_info.center_chan_2 = ie[4];
                        }
                        break;
+               case 255: /* Extension Tag*/
+                       nl80211_get_scanlist_extension(ie[1], ie + 2, e);
+                       break;
                }
 
                ielen -= ie[1] + 2;