devices: add device id for Realtek RTL8188CU and RTL8188FTV
[project/iwinfo.git] / iwinfo_cli.c
index 891f77e4f0bf67eed1f745989661c7460d263ff6..5dcee9ad023f4311fe75a7283d7c0bb788b6f976 100644 (file)
@@ -44,9 +44,20 @@ static char * format_ssid(char *ssid)
        return buf;
 }
 
+static const char *format_band(int band)
+{
+       const char *name;
+
+       name = iwinfo_band_name(band);
+       if (name)
+               return name;
+
+       return "unknown";
+}
+
 static char * format_channel(int ch)
 {
-       static char buf[8];
+       static char buf[16];
 
        if (ch <= 0)
                snprintf(buf, sizeof(buf), "unknown");
@@ -58,7 +69,7 @@ static char * format_channel(int ch)
 
 static char * format_frequency(int freq)
 {
-       static char buf[10];
+       static char buf[11];
 
        if (freq <= 0)
                snprintf(buf, sizeof(buf), "unknown");
@@ -68,9 +79,28 @@ static char * format_frequency(int freq)
        return buf;
 }
 
+static char * format_freqflags(uint32_t flags)
+{
+       static char str[512] = "[";
+       char *pos = str + 1;
+       int i;
+
+       if (!flags)
+               return "";
+
+       for (i = 0; i < IWINFO_FREQ_FLAG_COUNT; i++)
+               if (flags & (1 << i))
+                       pos += sprintf(pos, "%s, ", IWINFO_FREQ_FLAG_NAMES[i]);
+
+       *(pos - 2) = ']';
+       *(pos - 1) = 0;
+
+       return str;
+}
+
 static char * format_txpower(int pwr)
 {
-       static char buf[10];
+       static char buf[16];
 
        if (pwr < 0)
                snprintf(buf, sizeof(buf), "unknown");
@@ -82,7 +112,7 @@ static char * format_txpower(int pwr)
 
 static char * format_quality(int qual)
 {
-       static char buf[8];
+       static char buf[16];
 
        if (qual < 0)
                snprintf(buf, sizeof(buf), "unknown");
@@ -94,7 +124,7 @@ static char * format_quality(int qual)
 
 static char * format_quality_max(int qmax)
 {
-       static char buf[8];
+       static char buf[16];
 
        if (qmax < 0)
                snprintf(buf, sizeof(buf), "unknown");
@@ -130,7 +160,7 @@ static char * format_noise(int noise)
 
 static char * format_rate(int rate)
 {
-       static char buf[14];
+       static char buf[18];
 
        if (rate <= 0)
                snprintf(buf, sizeof(buf), "unknown");
@@ -145,30 +175,11 @@ static char * format_enc_ciphers(int ciphers)
 {
        static char str[128] = { 0 };
        char *pos = str;
+       int i;
 
-       if (ciphers & IWINFO_CIPHER_WEP40)
-               pos += sprintf(pos, "WEP-40, ");
-
-       if (ciphers & IWINFO_CIPHER_WEP104)
-               pos += sprintf(pos, "WEP-104, ");
-
-       if (ciphers & IWINFO_CIPHER_TKIP)
-               pos += sprintf(pos, "TKIP, ");
-
-       if (ciphers & IWINFO_CIPHER_CCMP)
-               pos += sprintf(pos, "CCMP, ");
-
-       if (ciphers & IWINFO_CIPHER_WRAP)
-               pos += sprintf(pos, "WRAP, ");
-
-       if (ciphers & IWINFO_CIPHER_AESOCB)
-               pos += sprintf(pos, "AES-OCB, ");
-
-       if (ciphers & IWINFO_CIPHER_CKIP)
-               pos += sprintf(pos, "CKIP, ");
-
-       if (!ciphers || (ciphers & IWINFO_CIPHER_NONE))
-               pos += sprintf(pos, "NONE, ");
+       for (i = 0; i < IWINFO_CIPHER_COUNT; i++)
+               if (ciphers & (1 << i))
+                       pos += sprintf(pos, "%s, ", IWINFO_CIPHER_NAMES[i]);
 
        *(pos - 2) = 0;
 
@@ -179,15 +190,11 @@ static char * format_enc_suites(int suites)
 {
        static char str[64] = { 0 };
        char *pos = str;
+       int i;
 
-       if (suites & IWINFO_KMGMT_PSK)
-               pos += sprintf(pos, "PSK/");
-
-       if (suites & IWINFO_KMGMT_8021x)
-               pos += sprintf(pos, "802.1X/");
-
-       if (!suites || (suites & IWINFO_KMGMT_NONE))
-               pos += sprintf(pos, "NONE/");
+       for (i = 0; i < IWINFO_KMGMT_COUNT; i++)
+               if (suites & (1 << i))
+                       pos += sprintf(pos, "%s/", IWINFO_KMGMT_NAMES[i]);
 
        *(pos - 1) = 0;
 
@@ -197,6 +204,8 @@ static char * format_enc_suites(int suites)
 static char * format_encryption(struct iwinfo_crypto_entry *c)
 {
        static char buf[512];
+       char *pos = buf;
+       int i, n;
 
        if (!c)
        {
@@ -228,25 +237,27 @@ static char * format_encryption(struct iwinfo_crypto_entry *c)
                /* WPA */
                else if (c->wpa_version)
                {
-                       switch (c->wpa_version) {
-                               case 3:
-                                       snprintf(buf, sizeof(buf), "mixed WPA/WPA2 %s (%s)",
-                                               format_enc_suites(c->auth_suites),
-                                               format_enc_ciphers(c->pair_ciphers | c->group_ciphers));
-                                       break;
-
-                               case 2:
-                                       snprintf(buf, sizeof(buf), "WPA2 %s (%s)",
-                                               format_enc_suites(c->auth_suites),
-                                               format_enc_ciphers(c->pair_ciphers | c->group_ciphers));
-                                       break;
-
-                               case 1:
-                                       snprintf(buf, sizeof(buf), "WPA %s (%s)",
-                                               format_enc_suites(c->auth_suites),
-                                               format_enc_ciphers(c->pair_ciphers | c->group_ciphers));
-                                       break;
-                       }
+                       for (i = 0, n = 0; i < 3; i++)
+                               if (c->wpa_version & (1 << i))
+                                       n++;
+
+                       if (n > 1)
+                               pos += sprintf(pos, "mixed ");
+
+                       for (i = 0; i < 3; i++)
+                               if (c->wpa_version & (1 << i))
+                               {
+                                       if (i)
+                                               pos += sprintf(pos, "WPA%d/", i + 1);
+                                       else
+                                               pos += sprintf(pos, "WPA/");
+                               }
+
+                       pos--;
+
+                       sprintf(pos, " %s (%s)",
+                               format_enc_suites(c->auth_suites),
+                               format_enc_ciphers(c->pair_ciphers | c->group_ciphers));
                }
                else
                {
@@ -263,24 +274,17 @@ static char * format_encryption(struct iwinfo_crypto_entry *c)
 
 static char * format_hwmodes(int modes)
 {
-       static char buf[12];
+       static char buf[32] = "802.11";
 
-       if (modes <= 0)
+       if (iwinfo_format_hwmodes(modes, buf + 6, sizeof(buf) - 6) < 1)
                snprintf(buf, sizeof(buf), "unknown");
-       else
-               snprintf(buf, sizeof(buf), "802.11%s%s%s%s%s",
-                       (modes & IWINFO_80211_A) ? "a" : "",
-                       (modes & IWINFO_80211_B) ? "b" : "",
-                       (modes & IWINFO_80211_G) ? "g" : "",
-                       (modes & IWINFO_80211_N) ? "n" : "",
-                       (modes & IWINFO_80211_AC) ? "ac" : "");
 
        return buf;
 }
 
 static char * format_assocrate(struct iwinfo_rate_entry *r)
 {
-       static char buf[40];
+       static char buf[80];
        char *p = buf;
        int l = sizeof(buf);
 
@@ -293,19 +297,60 @@ static char * format_assocrate(struct iwinfo_rate_entry *r)
                p += snprintf(p, l, "%s", format_rate(r->rate));
                l = sizeof(buf) - (p - buf);
 
-               if (r->mcs >= 0)
+               if (r->is_ht)
                {
-                       p += snprintf(p, l, ", MCS %d, %dMHz", r->mcs, 20 + r->is_40mhz*20);
+                       p += snprintf(p, l, ", MCS %d, %dMHz", r->mcs, r->mhz);
+                       l = sizeof(buf) - (p - buf);
+               }
+               else if (r->is_vht)
+               {
+                       p += snprintf(p, l, ", VHT-MCS %d, %dMHz", r->mcs, r->mhz);
+                       l = sizeof(buf) - (p - buf);
+
+                       if (r->nss)
+                       {
+                               p += snprintf(p, l, ", VHT-NSS %d", r->nss);
+                               l = sizeof(buf) - (p - buf);
+                       }
+               }
+               else if (r->is_he)
+               {
+                       p += snprintf(p, l, ", HE-MCS %d, %dMHz", r->mcs, r->mhz);
                        l = sizeof(buf) - (p - buf);
 
-                       if (r->is_short_gi)
-                               p += snprintf(p, l, ", short GI");
+                       p += snprintf(p, l, ", HE-NSS %d", r->nss);
+                       l = sizeof(buf) - (p - buf);
+
+                       p += snprintf(p, l, ", HE-GI %d", r->he_gi);
+                       l = sizeof(buf) - (p - buf);
+
+                       p += snprintf(p, l, ", HE-DCM %d", r->he_dcm);
+                       l = sizeof(buf) - (p - buf);
                }
        }
 
        return buf;
 }
 
+static const char* format_chan_width(bool vht, uint8_t width)
+{
+       if (!vht && width < ARRAY_SIZE(ht_chan_width))
+               switch (ht_chan_width[width]) {
+                       case 20: return "20 MHz";
+                       case 2040: return "40 MHz or higher";
+               }
+
+       if (vht && width < ARRAY_SIZE(vht_chan_width))
+               switch (vht_chan_width[width]) {
+                       case 40: return "20 or 40 MHz";
+                       case 80: return "80 MHz";
+                       case 8080: return "80+80 MHz";
+                       case 160: return "160 MHz";
+               }
+
+       return "unknown";
+}
+
 
 static const char * print_type(const struct iwinfo_ops *iw, const char *ifname)
 {
@@ -320,9 +365,16 @@ static char * print_hardware_id(const struct iwinfo_ops *iw, const char *ifname)
 
        if (!iw->hardware_id(ifname, (char *)&ids))
        {
-               snprintf(buf, sizeof(buf), "%04X:%04X %04X:%04X",
-                       ids.vendor_id, ids.device_id,
-                       ids.subsystem_vendor_id, ids.subsystem_device_id);
+               if (strlen(ids.compatible) > 0)
+                       snprintf(buf, sizeof(buf), "embedded");
+               else if (ids.vendor_id == 0 && ids.device_id == 0 &&
+                        ids.subsystem_vendor_id != 0 && ids.subsystem_device_id != 0)
+                       snprintf(buf, sizeof(buf), "USB %04X:%04X",
+                               ids.subsystem_vendor_id, ids.subsystem_device_id);
+               else
+                       snprintf(buf, sizeof(buf), "%04X:%04X %04X:%04X",
+                               ids.vendor_id, ids.device_id,
+                               ids.subsystem_vendor_id, ids.subsystem_device_id);
        }
        else
        {
@@ -414,6 +466,24 @@ static char * print_channel(const struct iwinfo_ops *iw, const char *ifname)
        return format_channel(ch);
 }
 
+static char * print_center_chan1(const struct iwinfo_ops *iw, const char *ifname)
+{
+       int ch;
+       if (iw->center_chan1(ifname, &ch))
+               ch = -1;
+
+       return format_channel(ch);
+}
+
+static char * print_center_chan2(const struct iwinfo_ops *iw, const char *ifname)
+{
+       int ch;
+       if (iw->center_chan2(ifname, &ch))
+               ch = -1;
+
+       return format_channel(ch);
+}
+
 static char * print_frequency(const struct iwinfo_ops *iw, const char *ifname)
 {
        int freq;
@@ -500,6 +570,20 @@ static char * print_hwmodes(const struct iwinfo_ops *iw, const char *ifname)
        return format_hwmodes(modes);
 }
 
+static const char *print_htmode(const struct iwinfo_ops *iw, const char *ifname)
+{
+       int mode;
+       const char *name;
+       if (iw->htmode(ifname, &mode))
+               mode = -1;
+
+       name = iwinfo_htmode_name(mode);
+       if (name)
+               return name;
+
+       return "unknown";
+}
+
 static char * print_mbssid_supp(const struct iwinfo_ops *iw, const char *ifname)
 {
        int supp;
@@ -531,10 +615,16 @@ static void print_info(const struct iwinfo_ops *iw, const char *ifname)
                print_ssid(iw, ifname));
        printf("          Access Point: %s\n",
                print_bssid(iw, ifname));
-       printf("          Mode: %s  Channel: %s (%s)\n",
+       printf("          Mode: %s  Channel: %s (%s)  HT Mode: %s\n",
                print_mode(iw, ifname),
                print_channel(iw, ifname),
-               print_frequency(iw, ifname));
+               print_frequency(iw, ifname),
+               print_htmode(iw, ifname));
+       if (iw->center_chan1 != NULL) {
+               printf("          Center Channel 1: %s",
+                       print_center_chan1(iw, ifname));
+               printf(" 2: %s\n", print_center_chan2(iw, ifname));
+       }
        printf("          Tx-Power: %s  Link Quality: %s/%s\n",
                print_txpower(iw, ifname),
                print_quality(iw, ifname),
@@ -588,15 +678,36 @@ static void print_scanlist(const struct iwinfo_ops *iw, const char *ifname)
                        format_bssid(e->mac));
                printf("          ESSID: %s\n",
                        format_ssid(e->ssid));
-               printf("          Mode: %s  Channel: %s\n",
+               printf("          Mode: %s  Frequency: %s  Band: %s  Channel: %s\n",
                        IWINFO_OPMODE_NAMES[e->mode],
+                       format_frequency(e->mhz),
+                       format_band(e->band),
                        format_channel(e->channel));
                printf("          Signal: %s  Quality: %s/%s\n",
                        format_signal(e->signal - 0x100),
                        format_quality(e->quality),
                        format_quality_max(e->quality_max));
-               printf("          Encryption: %s\n\n",
+               printf("          Encryption: %s\n",
                        format_encryption(&e->crypto));
+               printf("          HT Operation:\n");
+               printf("                    Primary Channel: %d\n",
+                       e->ht_chan_info.primary_chan);
+               printf("                    Secondary Channel Offset: %s\n",
+                       ht_secondary_offset[e->ht_chan_info.secondary_chan_off]);
+               printf("                    Channel Width: %s\n",
+                       format_chan_width(false, e->ht_chan_info.chan_width));
+
+               if (e->vht_chan_info.center_chan_1) {
+                       printf("          VHT Operation:\n");
+                       printf("                    Center Frequency 1: %d\n",
+                                e->vht_chan_info.center_chan_1);
+                       printf("                    Center Frequency 2: %d\n",
+                                e->vht_chan_info.center_chan_2);
+                       printf("                    Channel Width: %s\n",
+                               format_chan_width(true, e->vht_chan_info.chan_width));
+               }
+
+               printf("\n");
        }
 }
 
@@ -633,7 +744,7 @@ static void print_txpwrlist(const struct iwinfo_ops *iw, const char *ifname)
 
 static void print_freqlist(const struct iwinfo_ops *iw, const char *ifname)
 {
-       int i, len, ch;
+       int i, len, freq;
        char buf[IWINFO_BUFSIZE];
        struct iwinfo_freqlist_entry *e;
 
@@ -643,18 +754,19 @@ static void print_freqlist(const struct iwinfo_ops *iw, const char *ifname)
                return;
        }
 
-       if (iw->channel(ifname, &ch))
-               ch = -1;
+       if (iw->frequency(ifname, &freq))
+               freq = -1;
 
        for (i = 0; i < len; i += sizeof(struct iwinfo_freqlist_entry))
        {
                e = (struct iwinfo_freqlist_entry *) &buf[i];
 
-               printf("%s %s (Channel %s)%s\n",
-                       (ch == e->channel) ? "*" : " ",
+               printf("%s %s (Band: %s, Channel %s) %s\n",
+                       (freq == e->mhz) ? "*" : " ",
                        format_frequency(e->mhz),
+                       format_band(e->band),
                        format_channel(e->channel),
-                       e->restricted ? " [restricted]" : "");
+                       format_freqflags(e->flags));
        }
 }
 
@@ -692,10 +804,13 @@ static void print_assoclist(const struct iwinfo_ops *iw, const char *ifname)
                        e->rx_packets
                );
 
-               printf("        TX: %-38s  %8d Pkts.\n\n",
+               printf("        TX: %-38s  %8d Pkts.\n",
                        format_assocrate(&e->tx_rate),
                        e->tx_packets
                );
+
+               printf("        expected throughput: %s\n\n",
+                       format_rate(e->thr));
        }
 }
 
@@ -744,10 +859,56 @@ static void print_countrylist(const struct iwinfo_ops *iw, const char *ifname)
        }
 }
 
+static void print_htmodelist(const struct iwinfo_ops *iw, const char *ifname)
+{
+       int i, htmodes = 0;
+
+       if (iw->htmodelist(ifname, &htmodes))
+       {
+               printf("No HT mode information available\n");
+               return;
+       }
+
+       for (i = 0; i < IWINFO_HTMODE_COUNT; i++)
+               if (htmodes & (1 << i))
+                       printf("%s ", IWINFO_HTMODE_NAMES[i]);
+
+       printf("\n");
+}
+
+static void lookup_phy(const struct iwinfo_ops *iw, const char *section)
+{
+       char buf[IWINFO_BUFSIZE];
+
+       if (!iw->lookup_phy)
+       {
+               fprintf(stderr, "Not supported\n");
+               return;
+       }
+
+       if (iw->lookup_phy(section, buf))
+       {
+               fprintf(stderr, "Phy not found\n");
+               return;
+       }
+
+       printf("%s\n", buf);
+}
+
+
+static void lookup_path(const struct iwinfo_ops *iw, const char *phy)
+{
+       const char *path;
+
+       if (!iw->phy_path || iw->phy_path(phy, &path) || !path)
+               return;
+
+       printf("%s\n", path);
+}
 
 int main(int argc, char **argv)
 {
-       int i;
+       int i, rv = 0;
        char *p;
        const struct iwinfo_ops *iw;
        glob_t globbuf;
@@ -762,6 +923,8 @@ int main(int argc, char **argv)
                        "       iwinfo <device> freqlist\n"
                        "       iwinfo <device> assoclist\n"
                        "       iwinfo <device> countrylist\n"
+                       "       iwinfo <device> htmodelist\n"
+                       "       iwinfo <backend> phyname <section>\n"
                );
 
                return 1;
@@ -791,49 +954,85 @@ int main(int argc, char **argv)
                return 0;
        }
 
-       iw = iwinfo_backend(argv[1]);
-
-       if (!iw)
+       if (argc > 3)
        {
-               fprintf(stderr, "No such wireless device: %s\n", argv[1]);
-               return 1;
-       }
+               iw = iwinfo_backend_by_name(argv[1]);
+
+               if (!iw)
+               {
+                       fprintf(stderr, "No such wireless backend: %s\n", argv[1]);
+                       rv = 1;
+               }
+               else
+               {
+                       if (!strcmp(argv[2], "path")) {
+                               lookup_path(iw, argv[3]);
+                               return 0;
+                       }
+                       switch (argv[2][0])
+                       {
+                       case 'p':
+                               lookup_phy(iw, argv[3]);
+                               break;
 
-       for (i = 2; i < argc; i++)
+                       default:
+                               fprintf(stderr, "Unknown command: %s\n", argv[2]);
+                               rv = 1;
+                       }
+               }
+       }
+       else
        {
-               switch(argv[i][0])
+               iw = iwinfo_backend(argv[1]);
+
+               if (!iw)
                {
-               case 'i':
-                       print_info(iw, argv[1]);
-                       break;
+                       fprintf(stderr, "No such wireless device: %s\n", argv[1]);
+                       rv = 1;
+               }
+               else
+               {
+                       for (i = 2; i < argc; i++)
+                       {
+                               switch(argv[i][0])
+                               {
+                               case 'i':
+                                       print_info(iw, argv[1]);
+                                       break;
 
-               case 's':
-                       print_scanlist(iw, argv[1]);
-                       break;
+                               case 's':
+                                       print_scanlist(iw, argv[1]);
+                                       break;
 
-               case 't':
-                       print_txpwrlist(iw, argv[1]);
-                       break;
+                               case 't':
+                                       print_txpwrlist(iw, argv[1]);
+                                       break;
 
-               case 'f':
-                       print_freqlist(iw, argv[1]);
-                       break;
+                               case 'f':
+                                       print_freqlist(iw, argv[1]);
+                                       break;
 
-               case 'a':
-                       print_assoclist(iw, argv[1]);
-                       break;
+                               case 'a':
+                                       print_assoclist(iw, argv[1]);
+                                       break;
 
-               case 'c':
-                       print_countrylist(iw, argv[1]);
-                       break;
+                               case 'c':
+                                       print_countrylist(iw, argv[1]);
+                                       break;
+
+                               case 'h':
+                                       print_htmodelist(iw, argv[1]);
+                                       break;
 
-               default:
-                       fprintf(stderr, "Unknown command: %s\n", argv[i]);
-                       return 1;
+                               default:
+                                       fprintf(stderr, "Unknown command: %s\n", argv[i]);
+                                       rv = 1;
+                               }
+                       }
                }
        }
 
        iwinfo_finish();
 
-       return 0;
+       return rv;
 }