LCOV - code coverage report
Current view: top level - src/ap - ap_list.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1475438200 Lines: 151 164 92.1 %
Date: 2016-10-02 Functions: 13 13 100.0 %

          Line data    Source code
       1             : /*
       2             :  * hostapd / AP table
       3             :  * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
       4             :  * Copyright (c) 2003-2004, Instant802 Networks, Inc.
       5             :  * Copyright (c) 2006, Devicescape Software, Inc.
       6             :  *
       7             :  * This software may be distributed under the terms of the BSD license.
       8             :  * See README for more details.
       9             :  */
      10             : 
      11             : #include "utils/includes.h"
      12             : 
      13             : #include "utils/common.h"
      14             : #include "utils/eloop.h"
      15             : #include "common/ieee802_11_defs.h"
      16             : #include "common/ieee802_11_common.h"
      17             : #include "hostapd.h"
      18             : #include "ap_config.h"
      19             : #include "ieee802_11.h"
      20             : #include "sta_info.h"
      21             : #include "beacon.h"
      22             : #include "ap_list.h"
      23             : 
      24             : 
      25             : /* AP list is a double linked list with head->prev pointing to the end of the
      26             :  * list and tail->next = NULL. Entries are moved to the head of the list
      27             :  * whenever a beacon has been received from the AP in question. The tail entry
      28             :  * in this link will thus be the least recently used entry. */
      29             : 
      30             : 
      31       11612 : static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
      32             : {
      33             :         int i;
      34             : 
      35       23224 :         if (iface->current_mode == NULL ||
      36       23003 :             iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
      37       11391 :             iface->conf->channel != ap->channel)
      38         416 :                 return 0;
      39             : 
      40       11196 :         if (ap->erp != -1 && (ap->erp & ERP_INFO_NON_ERP_PRESENT))
      41           0 :                 return 1;
      42             : 
      43       54536 :         for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
      44       54535 :                 int rate = (ap->supported_rates[i] & 0x7f) * 5;
      45       54535 :                 if (rate == 60 || rate == 90 || rate > 110)
      46       11195 :                         return 0;
      47             :         }
      48             : 
      49           1 :         return 1;
      50             : }
      51             : 
      52             : 
      53       11618 : static struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
      54             : {
      55             :         struct ap_info *s;
      56             : 
      57       11618 :         s = iface->ap_hash[STA_HASH(ap)];
      58       23240 :         while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0)
      59           4 :                 s = s->hnext;
      60       11618 :         return s;
      61             : }
      62             : 
      63             : 
      64         703 : static void ap_ap_list_add(struct hostapd_iface *iface, struct ap_info *ap)
      65             : {
      66         703 :         if (iface->ap_list) {
      67         292 :                 ap->prev = iface->ap_list->prev;
      68         292 :                 iface->ap_list->prev = ap;
      69             :         } else
      70         411 :                 ap->prev = ap;
      71         703 :         ap->next = iface->ap_list;
      72         703 :         iface->ap_list = ap;
      73         703 : }
      74             : 
      75             : 
      76         703 : static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap)
      77             : {
      78         703 :         if (iface->ap_list == ap)
      79         418 :                 iface->ap_list = ap->next;
      80             :         else
      81         285 :                 ap->prev->next = ap->next;
      82             : 
      83         703 :         if (ap->next)
      84           7 :                 ap->next->prev = ap->prev;
      85         696 :         else if (iface->ap_list)
      86         285 :                 iface->ap_list->prev = ap->prev;
      87         703 : }
      88             : 
      89             : 
      90         440 : static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
      91             : {
      92         440 :         ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
      93         440 :         iface->ap_hash[STA_HASH(ap->addr)] = ap;
      94         440 : }
      95             : 
      96             : 
      97         440 : static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap)
      98             : {
      99             :         struct ap_info *s;
     100             : 
     101         440 :         s = iface->ap_hash[STA_HASH(ap->addr)];
     102         440 :         if (s == NULL) return;
     103         440 :         if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) {
     104         439 :                 iface->ap_hash[STA_HASH(ap->addr)] = s->hnext;
     105         439 :                 return;
     106             :         }
     107             : 
     108           3 :         while (s->hnext != NULL &&
     109           1 :                os_memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0)
     110           0 :                 s = s->hnext;
     111           1 :         if (s->hnext != NULL)
     112           1 :                 s->hnext = s->hnext->hnext;
     113             :         else
     114           0 :                 wpa_printf(MSG_INFO, "AP: could not remove AP " MACSTR
     115           0 :                            " from hash table",  MAC2STR(ap->addr));
     116             : }
     117             : 
     118             : 
     119         440 : static void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap)
     120             : {
     121         440 :         ap_ap_hash_del(iface, ap);
     122         440 :         ap_ap_list_del(iface, ap);
     123             : 
     124         440 :         iface->num_ap--;
     125         440 :         os_free(ap);
     126         440 : }
     127             : 
     128             : 
     129        2908 : static void hostapd_free_aps(struct hostapd_iface *iface)
     130             : {
     131             :         struct ap_info *ap, *prev;
     132             : 
     133        2908 :         ap = iface->ap_list;
     134             : 
     135        6233 :         while (ap) {
     136         417 :                 prev = ap;
     137         417 :                 ap = ap->next;
     138         417 :                 ap_free_ap(iface, prev);
     139             :         }
     140             : 
     141        2908 :         iface->ap_list = NULL;
     142        2908 : }
     143             : 
     144             : 
     145         441 : static struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr)
     146             : {
     147             :         struct ap_info *ap;
     148             : 
     149         441 :         ap = os_zalloc(sizeof(struct ap_info));
     150         441 :         if (ap == NULL)
     151           1 :                 return NULL;
     152             : 
     153             :         /* initialize AP info data */
     154         440 :         os_memcpy(ap->addr, addr, ETH_ALEN);
     155         440 :         ap_ap_list_add(iface, ap);
     156         440 :         iface->num_ap++;
     157         440 :         ap_ap_hash_add(iface, ap);
     158             : 
     159         440 :         if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) {
     160         132 :                 wpa_printf(MSG_DEBUG, "Removing the least recently used AP "
     161         132 :                            MACSTR " from AP table", MAC2STR(ap->prev->addr));
     162          22 :                 ap_free_ap(iface, ap->prev);
     163             :         }
     164             : 
     165         440 :         return ap;
     166             : }
     167             : 
     168             : 
     169       11630 : void ap_list_process_beacon(struct hostapd_iface *iface,
     170             :                             const struct ieee80211_mgmt *mgmt,
     171             :                             struct ieee802_11_elems *elems,
     172             :                             struct hostapd_frame_info *fi)
     173             : {
     174             :         struct ap_info *ap;
     175       11630 :         int new_ap = 0;
     176       11630 :         int set_beacon = 0;
     177             : 
     178       11630 :         if (iface->conf->ap_table_max_size < 1)
     179          12 :                 return;
     180             : 
     181       11618 :         ap = ap_get_ap(iface, mgmt->bssid);
     182       11618 :         if (!ap) {
     183         441 :                 ap = ap_ap_add(iface, mgmt->bssid);
     184         441 :                 if (!ap) {
     185           1 :                         wpa_printf(MSG_INFO,
     186             :                                    "Failed to allocate AP information entry");
     187           1 :                         return;
     188             :                 }
     189         440 :                 new_ap = 1;
     190             :         }
     191             : 
     192       23234 :         merge_byte_arrays(ap->supported_rates, WLAN_SUPP_RATES_MAX,
     193       11617 :                           elems->supp_rates, elems->supp_rates_len,
     194       11617 :                           elems->ext_supp_rates, elems->ext_supp_rates_len);
     195             : 
     196       11617 :         if (elems->erp_info)
     197       11496 :                 ap->erp = elems->erp_info[0];
     198             :         else
     199         121 :                 ap->erp = -1;
     200             : 
     201       11617 :         if (elems->ds_params)
     202       11617 :                 ap->channel = elems->ds_params[0];
     203           0 :         else if (elems->ht_operation)
     204           0 :                 ap->channel = elems->ht_operation[0];
     205           0 :         else if (fi)
     206           0 :                 ap->channel = fi->channel;
     207             : 
     208       11617 :         if (elems->ht_capabilities)
     209       11597 :                 ap->ht_support = 1;
     210             :         else
     211          20 :                 ap->ht_support = 0;
     212             : 
     213       11617 :         os_get_reltime(&ap->last_beacon);
     214             : 
     215       11617 :         if (!new_ap && ap != iface->ap_list) {
     216             :                 /* move AP entry into the beginning of the list so that the
     217             :                  * oldest entry is always in the end of the list */
     218         263 :                 ap_ap_list_del(iface, ap);
     219         263 :                 ap_ap_list_add(iface, ap);
     220             :         }
     221             : 
     222       23229 :         if (!iface->olbc &&
     223       11612 :             ap_list_beacon_olbc(iface, ap)) {
     224           1 :                 iface->olbc = 1;
     225           7 :                 wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR
     226             :                            " (channel %d) - enable protection",
     227           6 :                            MAC2STR(ap->addr), ap->channel);
     228           1 :                 set_beacon++;
     229             :         }
     230             : 
     231             : #ifdef CONFIG_IEEE80211N
     232       11624 :         if (!iface->olbc_ht && !ap->ht_support &&
     233          14 :             (ap->channel == 0 ||
     234           8 :              ap->channel == iface->conf->channel ||
     235           2 :              ap->channel == iface->conf->channel +
     236           1 :              iface->conf->secondary_channel * 4)) {
     237           6 :                 iface->olbc_ht = 1;
     238           6 :                 hostapd_ht_operation_update(iface);
     239          42 :                 wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR
     240             :                            " (channel %d) - enable protection",
     241          36 :                            MAC2STR(ap->addr), ap->channel);
     242           6 :                 set_beacon++;
     243             :         }
     244             : #endif /* CONFIG_IEEE80211N */
     245             : 
     246       11617 :         if (set_beacon)
     247           6 :                 ieee802_11_update_beacons(iface);
     248             : }
     249             : 
     250             : 
     251        2272 : void ap_list_timer(struct hostapd_iface *iface)
     252             : {
     253             :         struct os_reltime now;
     254             :         struct ap_info *ap;
     255        2272 :         int set_beacon = 0;
     256             : 
     257        2272 :         if (!iface->ap_list)
     258        4416 :                 return;
     259             : 
     260         128 :         os_get_reltime(&now);
     261             : 
     262         257 :         while (iface->ap_list) {
     263         128 :                 ap = iface->ap_list->prev;
     264         128 :                 if (!os_reltime_expired(&now, &ap->last_beacon,
     265         128 :                                         iface->conf->ap_table_expiration_time))
     266         127 :                         break;
     267             : 
     268           1 :                 ap_free_ap(iface, ap);
     269             :         }
     270             : 
     271         128 :         if (iface->olbc || iface->olbc_ht) {
     272           1 :                 int olbc = 0;
     273           1 :                 int olbc_ht = 0;
     274             : 
     275           1 :                 ap = iface->ap_list;
     276           2 :                 while (ap && (olbc == 0 || olbc_ht == 0)) {
     277           0 :                         if (ap_list_beacon_olbc(iface, ap))
     278           0 :                                 olbc = 1;
     279           0 :                         if (!ap->ht_support)
     280           0 :                                 olbc_ht = 1;
     281           0 :                         ap = ap->next;
     282             :                 }
     283           1 :                 if (!olbc && iface->olbc) {
     284           1 :                         wpa_printf(MSG_DEBUG, "OLBC not detected anymore");
     285           1 :                         iface->olbc = 0;
     286           1 :                         set_beacon++;
     287             :                 }
     288             : #ifdef CONFIG_IEEE80211N
     289           1 :                 if (!olbc_ht && iface->olbc_ht) {
     290           1 :                         wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore");
     291           1 :                         iface->olbc_ht = 0;
     292           1 :                         hostapd_ht_operation_update(iface);
     293           1 :                         set_beacon++;
     294             :                 }
     295             : #endif /* CONFIG_IEEE80211N */
     296             :         }
     297             : 
     298         128 :         if (set_beacon)
     299           1 :                 ieee802_11_update_beacons(iface);
     300             : }
     301             : 
     302             : 
     303        2602 : int ap_list_init(struct hostapd_iface *iface)
     304             : {
     305        2602 :         return 0;
     306             : }
     307             : 
     308             : 
     309        2908 : void ap_list_deinit(struct hostapd_iface *iface)
     310             : {
     311        2908 :         hostapd_free_aps(iface);
     312        2908 : }

Generated by: LCOV version 1.10