]> git.ipfire.org Git - thirdparty/iw.git/blobdiff - scan.c
update nl80211.h
[thirdparty/iw.git] / scan.c
diff --git a/scan.c b/scan.c
index 5f8ce93b529963fb8fb13ba2264907310695e573..2188166e8bde82819e7150266d9211a462b1de26 100644 (file)
--- a/scan.c
+++ b/scan.c
 #define WLAN_CAPABILITY_QOS            (1<<9)
 #define WLAN_CAPABILITY_SHORT_SLOT_TIME        (1<<10)
 #define WLAN_CAPABILITY_APSD           (1<<11)
+#define WLAN_CAPABILITY_RADIO_MEASURE  (1<<12)
 #define WLAN_CAPABILITY_DSSS_OFDM      (1<<13)
+#define WLAN_CAPABILITY_DEL_BACK       (1<<14)
+#define WLAN_CAPABILITY_IMM_BACK       (1<<15)
+/* DMG (60gHz) 802.11ad */
+/* type - bits 0..1 */
+#define WLAN_CAPABILITY_DMG_TYPE_MASK          (3<<0)
+
+#define WLAN_CAPABILITY_DMG_TYPE_IBSS          (1<<0) /* Tx by: STA */
+#define WLAN_CAPABILITY_DMG_TYPE_PBSS          (2<<0) /* Tx by: PCP */
+#define WLAN_CAPABILITY_DMG_TYPE_AP            (3<<0) /* Tx by: AP */
+
+#define WLAN_CAPABILITY_DMG_CBAP_ONLY          (1<<2)
+#define WLAN_CAPABILITY_DMG_CBAP_SOURCE                (1<<3)
+#define WLAN_CAPABILITY_DMG_PRIVACY            (1<<4)
+#define WLAN_CAPABILITY_DMG_ECPAC              (1<<5)
+
+#define WLAN_CAPABILITY_DMG_SPECTRUM_MGMT      (1<<8)
+#define WLAN_CAPABILITY_DMG_RADIO_MEASURE      (1<<12)
 
 static unsigned char ms_oui[3]         = { 0x00, 0x50, 0xf2 };
 static unsigned char ieee80211_oui[3]  = { 0x00, 0x0f, 0xac };
@@ -55,7 +73,8 @@ union ieee80211_country_ie_triplet {
 static int handle_scan(struct nl80211_state *state,
                       struct nl_cb *cb,
                       struct nl_msg *msg,
-                      int argc, char **argv)
+                      int argc, char **argv,
+                      enum id_input id)
 {
        struct nl_msg *ssids = NULL, *freqs = NULL;
        char *eptr;
@@ -72,6 +91,7 @@ static int handle_scan(struct nl80211_state *state,
        bool passive = false, have_ssids = false, have_freqs = false;
        size_t tmp;
        unsigned char *ies;
+       int flags = 0;
 
        ssids = nlmsg_alloc();
        if (!ssids)
@@ -93,6 +113,18 @@ static int handle_scan(struct nl80211_state *state,
                        } else if (strcmp(argv[i], "ies") == 0) {
                                parse = IES;
                                break;
+                       } else if (strcmp(argv[i], "lowpri") == 0) {
+                               parse = NONE;
+                               flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
+                               break;
+                       } else if (strcmp(argv[i], "flush") == 0) {
+                               parse = NONE;
+                               flags |= NL80211_SCAN_FLAG_FLUSH;
+                               break;
+                       } else if (strcmp(argv[i], "ap-force") == 0) {
+                               parse = NONE;
+                               flags |= NL80211_SCAN_FLAG_AP;
+                               break;
                        } else if (strcmp(argv[i], "ssid") == 0) {
                                parse = SSID;
                                have_ssids = true;
@@ -135,6 +167,8 @@ static int handle_scan(struct nl80211_state *state,
 
        if (have_freqs)
                nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
+       if (flags)
+               NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, flags);
 
        err = 0;
  nla_put_failure:
@@ -158,6 +192,7 @@ static void print_ssid(const uint8_t type, uint8_t len, const uint8_t *data)
        printf("\n");
 }
 
+#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
 #define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
 
 static void print_supprates(const uint8_t type, uint8_t len, const uint8_t *data)
@@ -169,7 +204,9 @@ static void print_supprates(const uint8_t type, uint8_t len, const uint8_t *data
        for (i = 0; i < len; i++) {
                int r = data[i] & 0x7f;
 
-               if (r == BSS_MEMBERSHIP_SELECTOR_HT_PHY && data[i] & 0x80)
+               if (r == BSS_MEMBERSHIP_SELECTOR_VHT_PHY && data[i] & 0x80)
+                       printf("VHT");
+               else if (r == BSS_MEMBERSHIP_SELECTOR_HT_PHY && data[i] & 0x80)
                        printf("HT");
                else
                        printf("%d.%d", r/2, 5*(r&1));
@@ -305,6 +342,9 @@ static void print_cipher(const uint8_t *data)
                case 6:
                        printf("AES-128-CMAC");
                        break;
+               case 8:
+                       printf("GCMP");
+                       break;
                default:
                        printf("%.02x-%.02x-%.02x:%d",
                                data[0], data[1] ,data[2], data[3]);
@@ -528,14 +568,15 @@ static void print_ht_capa(const uint8_t type, uint8_t len, const uint8_t *data)
        print_ht_mcs(data + 3);
 }
 
+static const char *ht_secondary_offset[4] = {
+       "no secondary",
+       "above",
+       "[reserved!]",
+       "below",
+};
+
 static void print_ht_op(const uint8_t type, uint8_t len, const uint8_t *data)
 {
-       static const char *offset[4] = {
-               "no secondary",
-               "above",
-               "[reserved!]",
-               "below",
-       };
        static const char *protection[4] = {
                "no",
                "nonmember",
@@ -550,7 +591,7 @@ static void print_ht_op(const uint8_t type, uint8_t len, const uint8_t *data)
        printf("\n");
        printf("\t\t * primary channel: %d\n", data[0]);
        printf("\t\t * secondary channel offset: %s\n",
-               offset[data[1] & 0x3]);
+               ht_secondary_offset[data[1] & 0x3]);
        printf("\t\t * STA channel width: %s\n", sta_chan_width[(data[1] & 0x4)>>2]);
        printf("\t\t * RIFS: %d\n", (data[1] & 0x8)>>3);
        printf("\t\t * HT protection: %s\n", protection[data[2] & 0x3]);
@@ -582,32 +623,60 @@ static void print_capabilities(const uint8_t type, uint8_t len, const uint8_t *d
                        else
                                first = false;
 
+#define CAPA(bit, name)                case bit: printf(" " name); break
+
                        switch (bit + base) {
-                       case 0:
-                               printf(" HT Information Exchange Supported");
-                               break;
-                       case 1:
-                               printf(" On-demand Beacon");
-                               break;
-                       case 2:
-                               printf(" Extended Channel Switching");
-                               break;
-                       case 3:
-                               printf(" Wave Indication");
-                               break;
-                       case 4:
-                               printf(" PSMP Capability");
-                               break;
-                       case 5:
-                               printf(" Service Interval Granularity");
-                               break;
-                       case 6:
-                               printf(" S-PSMP Capability");
-                               break;
+                       CAPA(0, "HT Information Exchange Supported");
+                       CAPA(1, "reserved (On-demand Beacon)");
+                       CAPA(2, "Extended Channel Switching");
+                       CAPA(3, "reserved (Wave Indication)");
+                       CAPA(4, "PSMP Capability");
+                       CAPA(5, "reserved (Service Interval Granularity)");
+                       CAPA(6, "S-PSMP Capability");
+                       CAPA(7, "Event");
+                       CAPA(8, "Diagnostics");
+                       CAPA(9, "Multicast Diagnostics");
+                       CAPA(10, "Location Tracking");
+                       CAPA(11, "FMS");
+                       CAPA(12, "Proxy ARP Service");
+                       CAPA(13, "Collocated Interference Reporting");
+                       CAPA(14, "Civic Location");
+                       CAPA(15, "Geospatial Location");
+                       CAPA(16, "TFS");
+                       CAPA(17, "WNM-Sleep Mode");
+                       CAPA(18, "TIM Broadcast");
+                       CAPA(19, "BSS Transition");
+                       CAPA(20, "QoS Traffic Capability");
+                       CAPA(21, "AC Station Count");
+                       CAPA(22, "Multiple BSSID");
+                       CAPA(23, "Timing Measurement");
+                       CAPA(24, "Channel Usage");
+                       CAPA(25, "SSID List");
+                       CAPA(26, "DMS");
+                       CAPA(27, "UTC TSF Offset");
+                       CAPA(28, "TDLS Peer U-APSD Buffer STA Support");
+                       CAPA(29, "TDLS Peer PSM Support");
+                       CAPA(30, "TDLS channel switching");
+                       CAPA(31, "Interworking");
+                       CAPA(32, "QoS Map");
+                       CAPA(33, "EBR");
+                       CAPA(34, "SSPN Interface");
+                       CAPA(35, "Reserved");
+                       CAPA(36, "MSGCF Capability");
+                       CAPA(37, "TDLS Support");
+                       CAPA(38, "TDLS Prohibited");
+                       CAPA(39, "TDLS Channel Switching Prohibited");
+                       CAPA(40, "Reject Unadmitted Frame");
+                       CAPA(44, "Identifier Location");
+                       CAPA(45, "U-APSD Coexistence");
+                       CAPA(46, "WNM-Notification");
+                       CAPA(47, "Reserved");
+                       CAPA(48, "UTF-8 SSID");
                        default:
                                printf(" %d", bit);
                                break;
                        }
+#undef CAPA
                }
        }
 
@@ -624,6 +693,60 @@ static void print_tim(const uint8_t type, uint8_t len, const uint8_t *data)
        printf("\n");
 }
 
+static void print_vht_capa(const uint8_t type, uint8_t len, const uint8_t *data)
+{
+       printf("\n");
+       print_vht_info(data[0] | (data[1] << 8) |
+                      (data[2] << 16) | (data[3] << 24),
+                      data + 4);
+}
+
+static void print_vht_oper(const uint8_t type, uint8_t len, const uint8_t *data)
+{
+       const char *chandwidths[] = {
+               [0] = "20 or 40 MHz",
+               [1] = "80 MHz",
+               [3] = "80+80 MHz",
+               [2] = "160 MHz",
+       };
+
+       printf("\n");
+       printf("\t\t * channel width: %d (%s)\n", data[0],
+               data[0] < ARRAY_SIZE(chandwidths) ? chandwidths[data[0]] : "unknown");
+       printf("\t\t * center freq segment 1: %d\n", data[1]);
+       printf("\t\t * center freq segment 2: %d\n", data[2]);
+       printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data[4], data[3]);
+}
+
+static void print_obss_scan_params(const uint8_t type, uint8_t len, const uint8_t *data)
+{
+       printf("\n");
+       printf("\t\t * passive dwell: %d TUs\n", (data[1] << 8) | data[0]);
+       printf("\t\t * active dwell: %d TUs\n", (data[3] << 8) | data[2]);
+       printf("\t\t * channel width trigger scan interval: %d s\n", (data[5] << 8) | data[4]);
+       printf("\t\t * scan passive total per channel: %d TUs\n", (data[7] << 8) | data[6]);
+       printf("\t\t * scan active total per channel: %d TUs\n", (data[9] << 8) | data[8]);
+       printf("\t\t * BSS width channel transition delay factor: %d\n", (data[11] << 8) | data[10]);
+       printf("\t\t * OBSS Scan Activity Threshold: %d.%02d %%\n",
+               ((data[13] << 8) | data[12]) / 100, ((data[13] << 8) | data[12]) % 100);
+}
+
+static void print_secchan_offs(const uint8_t type, uint8_t len, const uint8_t *data)
+{
+       if (data[0] < ARRAY_SIZE(ht_secondary_offset))
+               printf(" %s (%d)\n", ht_secondary_offset[data[0]], data[0]);
+       else
+               printf(" %d\n", data[0]);
+}
+
+static void print_bss_load(const uint8_t type, uint8_t len, const uint8_t *data)
+{
+       printf("\n");
+       printf("\t\t * station count: %d\n", (data[1] << 8) | data[0]);
+       printf("\t\t * channel utilisation: %d/255\n", data[2]);
+       printf("\t\t * available admission capacity: %d [*32us]\n", (data[4] << 8) | data[3]);
+}
+
 struct ie_print {
        const char *name;
        void (*print)(const uint8_t type, uint8_t len, const uint8_t *data);
@@ -669,10 +792,15 @@ static const struct ie_print ieprinters[] = {
        [3] = { "DS Parameter set", print_ds, 1, 1, BIT(PRINT_SCAN), },
        [5] = { "TIM", print_tim, 4, 255, BIT(PRINT_SCAN), },
        [7] = { "Country", print_country, 3, 255, BIT(PRINT_SCAN), },
+       [11] = { "BSS Load", print_bss_load, 5, 5, BIT(PRINT_SCAN), },
        [32] = { "Power constraint", print_powerconstraint, 1, 1, BIT(PRINT_SCAN), },
        [42] = { "ERP", print_erp, 1, 255, BIT(PRINT_SCAN), },
        [45] = { "HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN), },
+       [74] = { "Overlapping BSS scan params", print_obss_scan_params, 14, 255, BIT(PRINT_SCAN), },
        [61] = { "HT operation", print_ht_op, 22, 22, BIT(PRINT_SCAN), },
+       [62] = { "Secondary Channel Offset", print_secchan_offs, 1, 1, BIT(PRINT_SCAN), },
+       [191] = { "VHT capabilities", print_vht_capa, 12, 255, BIT(PRINT_SCAN), },
+       [192] = { "VHT operation", print_vht_oper, 5, 255, BIT(PRINT_SCAN), },
        [48] = { "RSN", print_rsn, 2, 255, BIT(PRINT_SCAN), },
        [50] = { "Extended supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
        [114] = { "MESH ID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
@@ -1106,6 +1234,70 @@ void print_ies(unsigned char *ie, int ielen, bool unknown,
        }
 }
 
+static void print_capa_dmg(__u16 capa)
+{
+       switch (capa & WLAN_CAPABILITY_DMG_TYPE_MASK) {
+       case WLAN_CAPABILITY_DMG_TYPE_AP:
+               printf(" DMG_ESS");
+               break;
+       case WLAN_CAPABILITY_DMG_TYPE_PBSS:
+               printf(" DMG_PCP");
+               break;
+       case WLAN_CAPABILITY_DMG_TYPE_IBSS:
+               printf(" DMG_IBSS");
+               break;
+       }
+
+       if (capa & WLAN_CAPABILITY_DMG_CBAP_ONLY)
+               printf(" CBAP_Only");
+       if (capa & WLAN_CAPABILITY_DMG_CBAP_SOURCE)
+               printf(" CBAP_Src");
+       if (capa & WLAN_CAPABILITY_DMG_PRIVACY)
+               printf(" Privacy");
+       if (capa & WLAN_CAPABILITY_DMG_ECPAC)
+               printf(" ECPAC");
+       if (capa & WLAN_CAPABILITY_DMG_SPECTRUM_MGMT)
+               printf(" SpectrumMgmt");
+       if (capa & WLAN_CAPABILITY_DMG_RADIO_MEASURE)
+               printf(" RadioMeasure");
+}
+
+static void print_capa_non_dmg(__u16 capa)
+{
+       if (capa & WLAN_CAPABILITY_ESS)
+               printf(" ESS");
+       if (capa & WLAN_CAPABILITY_IBSS)
+               printf(" IBSS");
+       if (capa & WLAN_CAPABILITY_CF_POLLABLE)
+               printf(" CfPollable");
+       if (capa & WLAN_CAPABILITY_CF_POLL_REQUEST)
+               printf(" CfPollReq");
+       if (capa & WLAN_CAPABILITY_PRIVACY)
+               printf(" Privacy");
+       if (capa & WLAN_CAPABILITY_SHORT_PREAMBLE)
+               printf(" ShortPreamble");
+       if (capa & WLAN_CAPABILITY_PBCC)
+               printf(" PBCC");
+       if (capa & WLAN_CAPABILITY_CHANNEL_AGILITY)
+               printf(" ChannelAgility");
+       if (capa & WLAN_CAPABILITY_SPECTRUM_MGMT)
+               printf(" SpectrumMgmt");
+       if (capa & WLAN_CAPABILITY_QOS)
+               printf(" QoS");
+       if (capa & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+               printf(" ShortSlotTime");
+       if (capa & WLAN_CAPABILITY_APSD)
+               printf(" APSD");
+       if (capa & WLAN_CAPABILITY_RADIO_MEASURE)
+               printf(" RadioMeasure");
+       if (capa & WLAN_CAPABILITY_DSSS_OFDM)
+               printf(" DSSS-OFDM");
+       if (capa & WLAN_CAPABILITY_DEL_BACK)
+               printf(" DelayedBACK");
+       if (capa & WLAN_CAPABILITY_IMM_BACK)
+               printf(" ImmediateBACK");
+}
+
 static int print_bss_handler(struct nl_msg *msg, void *arg)
 {
        struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -1127,6 +1319,7 @@ static int print_bss_handler(struct nl_msg *msg, void *arg)
        };
        struct scan_params *params = arg;
        int show = params->show_both_ie_sets ? 2 : 1;
+       bool is_dmg = false;
 
        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
                  genlmsg_attrlen(gnlh, 0), NULL);
@@ -1175,37 +1368,22 @@ static int print_bss_handler(struct nl_msg *msg, void *arg)
                        tsf, tsf/1000/1000/60/60/24, (tsf/1000/1000/60/60) % 24,
                        (tsf/1000/1000/60) % 60, (tsf/1000/1000) % 60);
        }
-       if (bss[NL80211_BSS_FREQUENCY])
-               printf("\tfreq: %d\n",
-                       nla_get_u32(bss[NL80211_BSS_FREQUENCY]));
+       if (bss[NL80211_BSS_FREQUENCY]) {
+               int freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+               printf("\tfreq: %d\n", freq);
+               if (freq > 45000)
+                       is_dmg = true;
+       }
        if (bss[NL80211_BSS_BEACON_INTERVAL])
                printf("\tbeacon interval: %d\n",
                        nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]));
        if (bss[NL80211_BSS_CAPABILITY]) {
                __u16 capa = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
                printf("\tcapability:");
-               if (capa & WLAN_CAPABILITY_ESS)
-                       printf(" ESS");
-               if (capa & WLAN_CAPABILITY_IBSS)
-                       printf(" IBSS");
-               if (capa & WLAN_CAPABILITY_PRIVACY)
-                       printf(" Privacy");
-               if (capa & WLAN_CAPABILITY_SHORT_PREAMBLE)
-                       printf(" ShortPreamble");
-               if (capa & WLAN_CAPABILITY_PBCC)
-                       printf(" PBCC");
-               if (capa & WLAN_CAPABILITY_CHANNEL_AGILITY)
-                       printf(" ChannelAgility");
-               if (capa & WLAN_CAPABILITY_SPECTRUM_MGMT)
-                       printf(" SpectrumMgmt");
-               if (capa & WLAN_CAPABILITY_QOS)
-                       printf(" QoS");
-               if (capa & WLAN_CAPABILITY_SHORT_SLOT_TIME)
-                       printf(" ShortSlotTime");
-               if (capa & WLAN_CAPABILITY_APSD)
-                       printf(" APSD");
-               if (capa & WLAN_CAPABILITY_DSSS_OFDM)
-                       printf(" DSSS-OFDM");
+               if (is_dmg)
+                       print_capa_dmg(capa);
+               else
+                       print_capa_non_dmg(capa);
                printf(" (0x%.4x)\n", capa);
        }
        if (bss[NL80211_BSS_SIGNAL_MBM]) {
@@ -1244,7 +1422,8 @@ static struct scan_params scan_params;
 static int handle_scan_dump(struct nl80211_state *state,
                            struct nl_cb *cb,
                            struct nl_msg *msg,
-                           int argc, char **argv)
+                           int argc, char **argv,
+                           enum id_input id)
 {
        if (argc > 1)
                return 1;
@@ -1266,7 +1445,8 @@ static int handle_scan_dump(struct nl80211_state *state,
 static int handle_scan_combined(struct nl80211_state *state,
                                struct nl_cb *cb,
                                struct nl_msg *msg,
-                               int argc, char **argv)
+                               int argc, char **argv,
+                               enum id_input id)
 {
        char **trig_argv;
        static char *dump_argv[] = {
@@ -1300,7 +1480,7 @@ static int handle_scan_combined(struct nl80211_state *state,
        int i;
        for (i = 0; i < argc - 2 - (dump_argc - 3); i++)
                trig_argv[i + 3] = argv[i + 2 + (dump_argc - 3)];
-       err = handle_cmd(state, II_NETDEV, trig_argc, trig_argv);
+       err = handle_cmd(state, id, trig_argc, trig_argv);
        free(trig_argv);
        if (err)
                return err;
@@ -1336,9 +1516,9 @@ static int handle_scan_combined(struct nl80211_state *state,
        }
 
        dump_argv[0] = argv[0];
-       return handle_cmd(state, II_NETDEV, dump_argc, dump_argv);
+       return handle_cmd(state, id, dump_argc, dump_argv);
 }
-TOPLEVEL(scan, "[-u] [freq <freq>*] [ies <hex as 00:11:..>] [ssid <ssid>*|passive]", 0, 0,
+TOPLEVEL(scan, "[-u] [freq <freq>*] [ies <hex as 00:11:..>] [lowpri,flush,ap-force] [ssid <ssid>*|passive]", 0, 0,
         CIB_NETDEV, handle_scan_combined,
         "Scan on the given frequencies and probe for the given SSIDs\n"
         "(or wildcard if not given) unless passive scanning is requested.\n"
@@ -1348,7 +1528,7 @@ COMMAND(scan, dump, "[-u]",
        NL80211_CMD_GET_SCAN, NLM_F_DUMP, CIB_NETDEV, handle_scan_dump,
        "Dump the current scan results. If -u is specified, print unknown\n"
        "data in scan results.");
-COMMAND(scan, trigger, "[freq <freq>*] [ies <hex as 00:11:..>] [ssid <ssid>*|passive]",
+COMMAND(scan, trigger, "[freq <freq>*] [ies <hex as 00:11:..>] [lowpri,flush,ap-force] [ssid <ssid>*|passive]",
        NL80211_CMD_TRIGGER_SCAN, 0, CIB_NETDEV, handle_scan,
         "Trigger a scan on the given frequencies with probing for the given\n"
         "SSIDs (or wildcard if not given) unless passive scanning is requested.");