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

          Line data    Source code
       1             : /*
       2             :  * hostapd - MBO
       3             :  * Copyright (c) 2016, Qualcomm Atheros, Inc.
       4             :  *
       5             :  * This software may be distributed under the terms of the BSD license.
       6             :  * See README for more details.
       7             :  */
       8             : 
       9             : #include "utils/includes.h"
      10             : 
      11             : #include "utils/common.h"
      12             : #include "common/ieee802_11_defs.h"
      13             : #include "common/ieee802_11_common.h"
      14             : #include "hostapd.h"
      15             : #include "sta_info.h"
      16             : #include "mbo_ap.h"
      17             : 
      18             : 
      19        4539 : void mbo_ap_sta_free(struct sta_info *sta)
      20             : {
      21             :         struct mbo_non_pref_chan_info *info, *prev;
      22             : 
      23        4539 :         info = sta->non_pref_chan;
      24        4539 :         sta->non_pref_chan = NULL;
      25        9085 :         while (info) {
      26           7 :                 prev = info;
      27           7 :                 info = info->next;
      28           7 :                 os_free(prev);
      29             :         }
      30        4539 : }
      31             : 
      32             : 
      33           8 : static void mbo_ap_parse_non_pref_chan(struct sta_info *sta,
      34             :                                        const u8 *buf, size_t len)
      35             : {
      36             :         struct mbo_non_pref_chan_info *info, *tmp;
      37             :         char channels[200], *pos, *end;
      38             :         size_t num_chan, i;
      39             :         int ret;
      40             : 
      41           8 :         if (len <= 3)
      42           2 :                 return; /* Not enough room for any channels */
      43             : 
      44           7 :         num_chan = len - 3;
      45           7 :         info = os_zalloc(sizeof(*info) + num_chan);
      46           7 :         if (!info)
      47           0 :                 return;
      48           7 :         info->op_class = buf[0];
      49           7 :         info->pref = buf[len - 2];
      50           7 :         info->reason_code = buf[len - 1];
      51           7 :         info->num_channels = num_chan;
      52           7 :         buf++;
      53           7 :         os_memcpy(info->channels, buf, num_chan);
      54           7 :         if (!sta->non_pref_chan) {
      55           4 :                 sta->non_pref_chan = info;
      56             :         } else {
      57           3 :                 tmp = sta->non_pref_chan;
      58           6 :                 while (tmp->next)
      59           0 :                         tmp = tmp->next;
      60           3 :                 tmp->next = info;
      61             :         }
      62             : 
      63           7 :         pos = channels;
      64           7 :         end = pos + sizeof(channels);
      65           7 :         *pos = '\0';
      66          17 :         for (i = 0; i < num_chan; i++) {
      67          10 :                 ret = os_snprintf(pos, end - pos, "%s%u",
      68          10 :                                   i == 0 ? "" : " ", buf[i]);
      69          10 :                 if (os_snprintf_error(end - pos, ret)) {
      70           0 :                         *pos = '\0';
      71           0 :                         break;
      72             :                 }
      73          10 :                 pos += ret;
      74             :         }
      75             : 
      76          63 :         wpa_printf(MSG_DEBUG, "MBO: STA " MACSTR
      77             :                    " non-preferred channel list (op class %u, pref %u, reason code %u, channels %s)",
      78          56 :                    MAC2STR(sta->addr), info->op_class, info->pref,
      79           7 :                    info->reason_code, channels);
      80             : }
      81             : 
      82             : 
      83        4756 : void mbo_ap_check_sta_assoc(struct hostapd_data *hapd, struct sta_info *sta,
      84             :                             struct ieee802_11_elems *elems)
      85             : {
      86             :         const u8 *pos, *attr, *end;
      87             :         size_t len;
      88             : 
      89        4756 :         if (!hapd->conf->mbo_enabled || !elems->mbo)
      90        9494 :                 return;
      91             : 
      92          18 :         pos = elems->mbo + 4;
      93          18 :         len = elems->mbo_len - 4;
      94          18 :         wpa_hexdump(MSG_DEBUG, "MBO: Association Request attributes", pos, len);
      95             : 
      96          18 :         attr = get_ie(pos, len, MBO_ATTR_ID_CELL_DATA_CAPA);
      97          18 :         if (attr && attr[1] >= 1)
      98          18 :                 sta->cell_capa = attr[2];
      99             : 
     100          18 :         mbo_ap_sta_free(sta);
     101          18 :         end = pos + len;
     102          56 :         while (end - pos > 1) {
     103          20 :                 u8 ie_len = pos[1];
     104             : 
     105          20 :                 if (2 + ie_len > end - pos)
     106           0 :                         break;
     107             : 
     108          20 :                 if (pos[0] == MBO_ATTR_ID_NON_PREF_CHAN_REPORT)
     109           2 :                         mbo_ap_parse_non_pref_chan(sta, pos + 2, ie_len);
     110          20 :                 pos += 2 + pos[1];
     111             :         }
     112             : }
     113             : 
     114             : 
     115         221 : int mbo_ap_get_info(struct sta_info *sta, char *buf, size_t buflen)
     116             : {
     117         221 :         char *pos = buf, *end = buf + buflen;
     118             :         int ret;
     119             :         struct mbo_non_pref_chan_info *info;
     120             :         u8 i;
     121         221 :         unsigned int count = 0;
     122             : 
     123         221 :         if (!sta->cell_capa)
     124         201 :                 return 0;
     125             : 
     126          20 :         ret = os_snprintf(pos, end - pos, "mbo_cell_capa=%u\n", sta->cell_capa);
     127          20 :         if (os_snprintf_error(end - pos, ret))
     128           0 :                 return pos - buf;
     129          20 :         pos += ret;
     130             : 
     131          27 :         for (info = sta->non_pref_chan; info; info = info->next) {
     132           7 :                 char *pos2 = pos;
     133             : 
     134          21 :                 ret = os_snprintf(pos2, end - pos2,
     135             :                                   "non_pref_chan[%u]=%u:%u:%u:",
     136          14 :                                   count, info->op_class, info->pref,
     137           7 :                                   info->reason_code);
     138           7 :                 count++;
     139           7 :                 if (os_snprintf_error(end - pos2, ret))
     140           0 :                         break;
     141           7 :                 pos2 += ret;
     142             : 
     143          17 :                 for (i = 0; i < info->num_channels; i++) {
     144          20 :                         ret = os_snprintf(pos2, end - pos2, "%u%s",
     145          10 :                                           info->channels[i],
     146          10 :                                           i + 1 < info->num_channels ?
     147             :                                           "," : "");
     148          10 :                         if (os_snprintf_error(end - pos2, ret)) {
     149           0 :                                 pos2 = NULL;
     150           0 :                                 break;
     151             :                         }
     152          10 :                         pos2 += ret;
     153             :                 }
     154             : 
     155           7 :                 if (!pos2)
     156           0 :                         break;
     157           7 :                 ret = os_snprintf(pos2, end - pos2, "\n");
     158           7 :                 if (os_snprintf_error(end - pos2, ret))
     159           0 :                         break;
     160           7 :                 pos2 += ret;
     161           7 :                 pos = pos2;
     162             :         }
     163             : 
     164          20 :         return pos - buf;
     165             : }
     166             : 
     167             : 
     168         258 : static void mbo_ap_wnm_notif_req_cell_capa(struct sta_info *sta,
     169             :                                            const u8 *buf, size_t len)
     170             : {
     171         258 :         if (len < 1)
     172         258 :                 return;
     173        1806 :         wpa_printf(MSG_DEBUG, "MBO: STA " MACSTR
     174             :                    " updated cellular data capability: %u",
     175        1806 :                    MAC2STR(sta->addr), buf[0]);
     176         258 :         sta->cell_capa = buf[0];
     177             : }
     178             : 
     179             : 
     180         264 : static void mbo_ap_wnm_notif_req_elem(struct sta_info *sta, u8 type,
     181             :                                       const u8 *buf, size_t len,
     182             :                                       int *first_non_pref_chan)
     183             : {
     184         264 :         switch (type) {
     185             :         case WFA_WNM_NOTIF_SUBELEM_NON_PREF_CHAN_REPORT:
     186           6 :                 if (*first_non_pref_chan) {
     187             :                         /*
     188             :                          * Need to free the previously stored entries now to
     189             :                          * allow the update to replace all entries.
     190             :                          */
     191           4 :                         *first_non_pref_chan = 0;
     192           4 :                         mbo_ap_sta_free(sta);
     193             :                 }
     194           6 :                 mbo_ap_parse_non_pref_chan(sta, buf, len);
     195           6 :                 break;
     196             :         case WFA_WNM_NOTIF_SUBELEM_CELL_DATA_CAPA:
     197         258 :                 mbo_ap_wnm_notif_req_cell_capa(sta, buf, len);
     198         258 :                 break;
     199             :         default:
     200           0 :                 wpa_printf(MSG_DEBUG,
     201             :                            "MBO: Ignore unknown WNM Notification WFA subelement %u",
     202             :                            type);
     203           0 :                 break;
     204             :         }
     205         264 : }
     206             : 
     207             : 
     208         262 : void mbo_ap_wnm_notification_req(struct hostapd_data *hapd, const u8 *addr,
     209             :                                  const u8 *buf, size_t len)
     210             : {
     211             :         const u8 *pos, *end;
     212             :         u8 ie_len;
     213             :         struct sta_info *sta;
     214         262 :         int first_non_pref_chan = 1;
     215             : 
     216         262 :         if (!hapd->conf->mbo_enabled)
     217           0 :                 return;
     218             : 
     219         262 :         sta = ap_get_sta(hapd, addr);
     220         262 :         if (!sta)
     221           0 :                 return;
     222             : 
     223         262 :         pos = buf;
     224         262 :         end = buf + len;
     225             : 
     226         788 :         while (end - pos > 1) {
     227         264 :                 ie_len = pos[1];
     228             : 
     229         264 :                 if (2 + ie_len > end - pos)
     230           0 :                         break;
     231             : 
     232         264 :                 if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
     233         264 :                     ie_len >= 4 && WPA_GET_BE24(pos + 2) == OUI_WFA)
     234         264 :                         mbo_ap_wnm_notif_req_elem(sta, pos[5],
     235         264 :                                                   pos + 6, ie_len - 4,
     236             :                                                   &first_non_pref_chan);
     237             :                 else
     238           0 :                         wpa_printf(MSG_DEBUG,
     239             :                                    "MBO: Ignore unknown WNM Notification element %u (len=%u)",
     240           0 :                                    pos[0], pos[1]);
     241             : 
     242         264 :                 pos += 2 + pos[1];
     243             :         }
     244             : }

Generated by: LCOV version 1.10