LCOV - code coverage report
Current view: top level - src/ap - taxonomy.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1475438200 Lines: 114 128 89.1 %
Date: 2016-10-02 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /*
       2             :  * hostapd / Client taxonomy
       3             :  * Copyright (c) 2015 Google, Inc.
       4             :  *
       5             :  * This software may be distributed under the terms of the BSD license.
       6             :  * See README for more details.
       7             :  *
       8             :  * Parse a series of IEs, as in Probe Request or (Re)Association Request frames,
       9             :  * and render them to a descriptive string. The tag number of standard options
      10             :  * is written to the string, while the vendor ID and subtag are written for
      11             :  * vendor options.
      12             :  *
      13             :  * Example strings:
      14             :  * 0,1,50,45,221(00904c,51)
      15             :  * 0,1,33,36,48,45,221(00904c,51),221(0050f2,2)
      16             :  */
      17             : 
      18             : #include "utils/includes.h"
      19             : 
      20             : #include "utils/common.h"
      21             : #include "common/wpa_ctrl.h"
      22             : #include "hostapd.h"
      23             : #include "sta_info.h"
      24             : 
      25             : 
      26             : /* Copy a string with no funny schtuff allowed; only alphanumerics. */
      27           2 : static void no_mischief_strncpy(char *dst, const char *src, size_t n)
      28             : {
      29             :         size_t i;
      30             : 
      31          13 :         for (i = 0; i < n; i++) {
      32          11 :                 unsigned char s = src[i];
      33          11 :                 int is_lower = s >= 'a' && s <= 'z';
      34          11 :                 int is_upper = s >= 'A' && s <= 'Z';
      35          11 :                 int is_digit = s >= '0' && s <= '9';
      36             : 
      37          11 :                 if (is_lower || is_upper || is_digit) {
      38             :                         /* TODO: if any manufacturer uses Unicode within the
      39             :                          * WPS header, it will get mangled here. */
      40           9 :                         dst[i] = s;
      41             :                 } else {
      42             :                         /* Note that even spaces will be transformed to
      43             :                          * underscores, so 'Nexus 7' will turn into 'Nexus_7'.
      44             :                          * This is deliberate, to make the string easier to
      45             :                          * parse. */
      46           2 :                         dst[i] = '_';
      47             :                 }
      48             :         }
      49           2 : }
      50             : 
      51             : 
      52           2 : static int get_wps_name(char *name, size_t name_len,
      53             :                         const u8 *data, size_t data_len)
      54             : {
      55             :         /* Inside the WPS IE are a series of attributes, using two byte IDs
      56             :          * and two byte lengths. We're looking for the model name, if
      57             :          * present. */
      58          24 :         while (data_len >= 4) {
      59             :                 u16 id, elen;
      60             : 
      61          22 :                 id = WPA_GET_BE16(data);
      62          22 :                 elen = WPA_GET_BE16(data + 2);
      63          22 :                 data += 4;
      64          22 :                 data_len -= 4;
      65             : 
      66          22 :                 if (elen > data_len)
      67           0 :                         return 0;
      68             : 
      69          22 :                 if (id == 0x1023) {
      70             :                         /* Model name, like 'Nexus 7' */
      71           2 :                         size_t n = (elen < name_len) ? elen : name_len;
      72           2 :                         no_mischief_strncpy(name, (const char *) data, n);
      73           2 :                         return n;
      74             :                 }
      75             : 
      76          20 :                 data += elen;
      77          20 :                 data_len -= elen;
      78             :         }
      79             : 
      80           0 :         return 0;
      81             : }
      82             : 
      83             : 
      84           8 : static void ie_to_string(char *fstr, size_t fstr_len, const struct wpabuf *ies)
      85             : {
      86           8 :         char *fpos = fstr;
      87           8 :         char *fend = fstr + fstr_len;
      88             :         char htcap[7 + 4 + 1]; /* ",htcap:" + %04hx + trailing NUL */
      89             :         char htagg[7 + 2 + 1]; /* ",htagg:" + %02hx + trailing NUL */
      90             :         char htmcs[7 + 8 + 1]; /* ",htmcs:" + %08x + trailing NUL */
      91             :         char vhtcap[8 + 8 + 1]; /* ",vhtcap:" + %08x + trailing NUL */
      92             :         char vhtrxmcs[10 + 8 + 1]; /* ",vhtrxmcs:" + %08x + trailing NUL */
      93             :         char vhttxmcs[10 + 8 + 1]; /* ",vhttxmcs:" + %08x + trailing NUL */
      94             : #define MAX_EXTCAP      254
      95             :         char extcap[8 + 2 * MAX_EXTCAP + 1]; /* ",extcap:" + hex + trailing NUL
      96             :                                               */
      97             :         char txpow[7 + 4 + 1]; /* ",txpow:" + %04hx + trailing NUL */
      98             : #define WPS_NAME_LEN            32
      99             :         char wps[WPS_NAME_LEN + 5 + 1]; /* room to prepend ",wps:" + trailing
     100             :                                          * NUL */
     101           8 :         int num = 0;
     102             :         const u8 *ie;
     103             :         size_t ie_len;
     104             :         int ret;
     105             : 
     106           8 :         os_memset(htcap, 0, sizeof(htcap));
     107           8 :         os_memset(htagg, 0, sizeof(htagg));
     108           8 :         os_memset(htmcs, 0, sizeof(htmcs));
     109           8 :         os_memset(vhtcap, 0, sizeof(vhtcap));
     110           8 :         os_memset(vhtrxmcs, 0, sizeof(vhtrxmcs));
     111           8 :         os_memset(vhttxmcs, 0, sizeof(vhttxmcs));
     112           8 :         os_memset(extcap, 0, sizeof(extcap));
     113           8 :         os_memset(txpow, 0, sizeof(txpow));
     114           8 :         os_memset(wps, 0, sizeof(wps));
     115           8 :         *fpos = '\0';
     116             : 
     117           8 :         if (!ies)
     118           8 :                 return;
     119           8 :         ie = wpabuf_head(ies);
     120           8 :         ie_len = wpabuf_len(ies);
     121             : 
     122          72 :         while (ie_len >= 2) {
     123             :                 u8 id, elen;
     124          56 :                 char *sep = (num++ == 0) ? "" : ",";
     125             : 
     126          56 :                 id = *ie++;
     127          56 :                 elen = *ie++;
     128          56 :                 ie_len -= 2;
     129             : 
     130          56 :                 if (elen > ie_len)
     131           0 :                         break;
     132             : 
     133          56 :                 if (id == WLAN_EID_VENDOR_SPECIFIC && elen >= 4) {
     134             :                         /* Vendor specific */
     135          11 :                         if (WPA_GET_BE32(ie) == WPS_IE_VENDOR_TYPE) {
     136             :                                 /* WPS */
     137             :                                 char model_name[WPS_NAME_LEN + 1];
     138           2 :                                 const u8 *data = &ie[4];
     139           2 :                                 size_t data_len = elen - 4;
     140             : 
     141           2 :                                 os_memset(model_name, 0, sizeof(model_name));
     142           2 :                                 if (get_wps_name(model_name, WPS_NAME_LEN, data,
     143             :                                                  data_len)) {
     144           2 :                                         os_snprintf(wps, sizeof(wps),
     145             :                                                     ",wps:%s", model_name);
     146             :                                 }
     147             :                         }
     148             : 
     149          44 :                         ret = os_snprintf(fpos, fend - fpos,
     150             :                                           "%s%d(%02x%02x%02x,%d)",
     151          44 :                                           sep, id, ie[0], ie[1], ie[2], ie[3]);
     152             :                 } else {
     153          45 :                         if (id == WLAN_EID_HT_CAP && elen >= 2) {
     154             :                                 /* HT Capabilities (802.11n) */
     155           8 :                                 os_snprintf(htcap, sizeof(htcap),
     156             :                                             ",htcap:%04hx",
     157           8 :                                             WPA_GET_LE16(ie));
     158             :                         }
     159          45 :                         if (id == WLAN_EID_HT_CAP && elen >= 3) {
     160             :                                 /* HT Capabilities (802.11n), A-MPDU information
     161             :                                  */
     162           8 :                                 os_snprintf(htagg, sizeof(htagg),
     163           8 :                                             ",htagg:%02hx", (u16) ie[2]);
     164             :                         }
     165          45 :                         if (id == WLAN_EID_HT_CAP && elen >= 7) {
     166             :                                 /* HT Capabilities (802.11n), MCS information */
     167           8 :                                 os_snprintf(htmcs, sizeof(htmcs),
     168             :                                             ",htmcs:%08hx",
     169           8 :                                             (u16) WPA_GET_LE32(ie + 3));
     170             :                         }
     171          45 :                         if (id == WLAN_EID_VHT_CAP && elen >= 4) {
     172             :                                 /* VHT Capabilities (802.11ac) */
     173           0 :                                 os_snprintf(vhtcap, sizeof(vhtcap),
     174             :                                             ",vhtcap:%08x",
     175             :                                             WPA_GET_LE32(ie));
     176             :                         }
     177          45 :                         if (id == WLAN_EID_VHT_CAP && elen >= 8) {
     178             :                                 /* VHT Capabilities (802.11ac), RX MCS
     179             :                                  * information */
     180           0 :                                 os_snprintf(vhtrxmcs, sizeof(vhtrxmcs),
     181             :                                             ",vhtrxmcs:%08x",
     182             :                                             WPA_GET_LE32(ie + 4));
     183             :                         }
     184          45 :                         if (id == WLAN_EID_VHT_CAP && elen >= 12) {
     185             :                                 /* VHT Capabilities (802.11ac), TX MCS
     186             :                                  * information */
     187           0 :                                 os_snprintf(vhttxmcs, sizeof(vhttxmcs),
     188             :                                             ",vhttxmcs:%08x",
     189             :                                             WPA_GET_LE32(ie + 8));
     190             :                         }
     191          45 :                         if (id == WLAN_EID_EXT_CAPAB) {
     192             :                                 /* Extended Capabilities */
     193             :                                 int i;
     194           7 :                                 int len = (elen < MAX_EXTCAP) ? elen :
     195             :                                         MAX_EXTCAP;
     196           7 :                                 char *p = extcap;
     197             : 
     198           7 :                                 p += os_snprintf(extcap, sizeof(extcap),
     199             :                                                  ",extcap:");
     200          63 :                                 for (i = 0; i < len; i++) {
     201             :                                         int lim;
     202             : 
     203          56 :                                         lim = sizeof(extcap) -
     204          56 :                                                 os_strlen(extcap);
     205          56 :                                         if (lim <= 0)
     206           0 :                                                 break;
     207          56 :                                         p += os_snprintf(p, lim, "%02x",
     208          56 :                                                          *(ie + i));
     209             :                                 }
     210             :                         }
     211          45 :                         if (id == WLAN_EID_PWR_CAPABILITY && elen == 2) {
     212             :                                 /* TX Power */
     213           0 :                                 os_snprintf(txpow, sizeof(txpow),
     214             :                                             ",txpow:%04hx",
     215           0 :                                             WPA_GET_LE16(ie));
     216             :                         }
     217             : 
     218          45 :                         ret = os_snprintf(fpos, fend - fpos, "%s%d", sep, id);
     219             :                 }
     220          56 :                 if (os_snprintf_error(fend - fpos, ret))
     221           0 :                         goto fail;
     222          56 :                 fpos += ret;
     223             : 
     224          56 :                 ie += elen;
     225          56 :                 ie_len -= elen;
     226             :         }
     227             : 
     228           8 :         ret = os_snprintf(fpos, fend - fpos, "%s%s%s%s%s%s%s%s%s",
     229             :                           htcap, htagg, htmcs, vhtcap, vhtrxmcs, vhttxmcs,
     230             :                           txpow, extcap, wps);
     231           8 :         if (os_snprintf_error(fend - fpos, ret)) {
     232             :         fail:
     233           0 :                 fstr[0] = '\0';
     234             :         }
     235             : }
     236             : 
     237             : 
     238           5 : int retrieve_sta_taxonomy(const struct hostapd_data *hapd,
     239             :                           struct sta_info *sta, char *buf, size_t buflen)
     240             : {
     241             :         int ret;
     242             :         char *pos, *end;
     243             : 
     244           5 :         if (!sta->probe_ie_taxonomy || !sta->assoc_ie_taxonomy)
     245           1 :                 return 0;
     246             : 
     247           4 :         ret = os_snprintf(buf, buflen, "wifi4|probe:");
     248           4 :         if (os_snprintf_error(buflen, ret))
     249           0 :                 return 0;
     250           4 :         pos = buf + ret;
     251           4 :         end = buf + buflen;
     252             : 
     253           4 :         ie_to_string(pos, end - pos, sta->probe_ie_taxonomy);
     254           4 :         pos = os_strchr(pos, '\0');
     255           4 :         if (pos >= end)
     256           0 :                 return 0;
     257           4 :         ret = os_snprintf(pos, end - pos, "|assoc:");
     258           4 :         if (os_snprintf_error(end - pos, ret))
     259           0 :                 return 0;
     260           4 :         pos += ret;
     261           4 :         ie_to_string(pos, end - pos, sta->assoc_ie_taxonomy);
     262           4 :         pos = os_strchr(pos, '\0');
     263           4 :         return pos - buf;
     264             : }
     265             : 
     266             : 
     267         495 : void taxonomy_sta_info_probe_req(const struct hostapd_data *hapd,
     268             :                                  struct sta_info *sta,
     269             :                                  const u8 *ie, size_t ie_len)
     270             : {
     271         495 :         wpabuf_free(sta->probe_ie_taxonomy);
     272         495 :         sta->probe_ie_taxonomy = wpabuf_alloc_copy(ie, ie_len);
     273         495 : }
     274             : 
     275             : 
     276          21 : void taxonomy_hostapd_sta_info_probe_req(const struct hostapd_data *hapd,
     277             :                                          struct hostapd_sta_info *info,
     278             :                                          const u8 *ie, size_t ie_len)
     279             : {
     280          21 :         wpabuf_free(info->probe_ie_taxonomy);
     281          21 :         info->probe_ie_taxonomy = wpabuf_alloc_copy(ie, ie_len);
     282          21 : }
     283             : 
     284             : 
     285        4180 : void taxonomy_sta_info_assoc_req(const struct hostapd_data *hapd,
     286             :                                  struct sta_info *sta,
     287             :                                  const u8 *ie, size_t ie_len)
     288             : {
     289        4180 :         wpabuf_free(sta->assoc_ie_taxonomy);
     290        4180 :         sta->assoc_ie_taxonomy = wpabuf_alloc_copy(ie, ie_len);
     291        4180 : }

Generated by: LCOV version 1.10