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 1443382998 Lines: 151 164 92.1 %
Date: 2015-09-27 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        8582 : static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
      32             : {
      33             :         int i;
      34             : 
      35       17164 :         if (iface->current_mode == NULL ||
      36       17062 :             iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
      37        8480 :             iface->conf->channel != ap->channel)
      38         123 :                 return 0;
      39             : 
      40        8459 :         if (ap->erp != -1 && (ap->erp & ERP_INFO_NON_ERP_PRESENT))
      41           0 :                 return 1;
      42             : 
      43       41147 :         for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
      44       41146 :                 int rate = (ap->supported_rates[i] & 0x7f) * 5;
      45       41146 :                 if (rate == 60 || rate == 90 || rate > 110)
      46        8458 :                         return 0;
      47             :         }
      48             : 
      49           1 :         return 1;
      50             : }
      51             : 
      52             : 
      53        8587 : static struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
      54             : {
      55             :         struct ap_info *s;
      56             : 
      57        8587 :         s = iface->ap_hash[STA_HASH(ap)];
      58       17211 :         while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0)
      59          37 :                 s = s->hnext;
      60        8587 :         return s;
      61             : }
      62             : 
      63             : 
      64         407 : static void ap_ap_list_add(struct hostapd_iface *iface, struct ap_info *ap)
      65             : {
      66         407 :         if (iface->ap_list) {
      67          95 :                 ap->prev = iface->ap_list->prev;
      68          95 :                 iface->ap_list->prev = ap;
      69             :         } else
      70         312 :                 ap->prev = ap;
      71         407 :         ap->next = iface->ap_list;
      72         407 :         iface->ap_list = ap;
      73         407 : }
      74             : 
      75             : 
      76         407 : static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap)
      77             : {
      78         407 :         if (iface->ap_list == ap)
      79         318 :                 iface->ap_list = ap->next;
      80             :         else
      81          89 :                 ap->prev->next = ap->next;
      82             : 
      83         407 :         if (ap->next)
      84           6 :                 ap->next->prev = ap->prev;
      85         401 :         else if (iface->ap_list)
      86          89 :                 iface->ap_list->prev = ap->prev;
      87         407 : }
      88             : 
      89             : 
      90         340 : static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
      91             : {
      92         340 :         ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
      93         340 :         iface->ap_hash[STA_HASH(ap->addr)] = ap;
      94         340 : }
      95             : 
      96             : 
      97         340 : static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap)
      98             : {
      99             :         struct ap_info *s;
     100             : 
     101         340 :         s = iface->ap_hash[STA_HASH(ap->addr)];
     102         340 :         if (s == NULL) return;
     103         340 :         if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) {
     104         338 :                 iface->ap_hash[STA_HASH(ap->addr)] = s->hnext;
     105         338 :                 return;
     106             :         }
     107             : 
     108           6 :         while (s->hnext != NULL &&
     109           2 :                os_memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0)
     110           0 :                 s = s->hnext;
     111           2 :         if (s->hnext != NULL)
     112           2 :                 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         340 : static void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap)
     120             : {
     121         340 :         ap_ap_hash_del(iface, ap);
     122         340 :         ap_ap_list_del(iface, ap);
     123             : 
     124         340 :         iface->num_ap--;
     125         340 :         os_free(ap);
     126         340 : }
     127             : 
     128             : 
     129        2235 : static void hostapd_free_aps(struct hostapd_iface *iface)
     130             : {
     131             :         struct ap_info *ap, *prev;
     132             : 
     133        2235 :         ap = iface->ap_list;
     134             : 
     135        4787 :         while (ap) {
     136         317 :                 prev = ap;
     137         317 :                 ap = ap->next;
     138         317 :                 ap_free_ap(iface, prev);
     139             :         }
     140             : 
     141        2235 :         iface->ap_list = NULL;
     142        2235 : }
     143             : 
     144             : 
     145         341 : static struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr)
     146             : {
     147             :         struct ap_info *ap;
     148             : 
     149         341 :         ap = os_zalloc(sizeof(struct ap_info));
     150         341 :         if (ap == NULL)
     151           1 :                 return NULL;
     152             : 
     153             :         /* initialize AP info data */
     154         340 :         os_memcpy(ap->addr, addr, ETH_ALEN);
     155         340 :         ap_ap_list_add(iface, ap);
     156         340 :         iface->num_ap++;
     157         340 :         ap_ap_hash_add(iface, ap);
     158             : 
     159         340 :         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         340 :         return ap;
     166             : }
     167             : 
     168             : 
     169        8599 : 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        8599 :         int new_ap = 0;
     176        8599 :         int set_beacon = 0;
     177             : 
     178        8599 :         if (iface->conf->ap_table_max_size < 1)
     179          12 :                 return;
     180             : 
     181        8587 :         ap = ap_get_ap(iface, mgmt->bssid);
     182        8587 :         if (!ap) {
     183         341 :                 ap = ap_ap_add(iface, mgmt->bssid);
     184         341 :                 if (!ap) {
     185           1 :                         wpa_printf(MSG_INFO,
     186             :                                    "Failed to allocate AP information entry");
     187           1 :                         return;
     188             :                 }
     189         340 :                 new_ap = 1;
     190             :         }
     191             : 
     192       17172 :         merge_byte_arrays(ap->supported_rates, WLAN_SUPP_RATES_MAX,
     193        8586 :                           elems->supp_rates, elems->supp_rates_len,
     194        8586 :                           elems->ext_supp_rates, elems->ext_supp_rates_len);
     195             : 
     196        8586 :         if (elems->erp_info)
     197        8484 :                 ap->erp = elems->erp_info[0];
     198             :         else
     199         102 :                 ap->erp = -1;
     200             : 
     201        8586 :         if (elems->ds_params)
     202        8586 :                 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        8586 :         if (elems->ht_capabilities)
     209        8568 :                 ap->ht_support = 1;
     210             :         else
     211          18 :                 ap->ht_support = 0;
     212             : 
     213        8586 :         os_get_reltime(&ap->last_beacon);
     214             : 
     215        8586 :         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          67 :                 ap_ap_list_del(iface, ap);
     219          67 :                 ap_ap_list_add(iface, ap);
     220             :         }
     221             : 
     222       17168 :         if (!iface->olbc &&
     223        8582 :             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        8593 :         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        8586 :         if (set_beacon)
     247           6 :                 ieee802_11_update_beacons(iface);
     248             : }
     249             : 
     250             : 
     251        1749 : void ap_list_timer(struct hostapd_iface *iface)
     252             : {
     253             :         struct os_reltime now;
     254             :         struct ap_info *ap;
     255        1749 :         int set_beacon = 0;
     256             : 
     257        1749 :         if (!iface->ap_list)
     258        3406 :                 return;
     259             : 
     260          92 :         os_get_reltime(&now);
     261             : 
     262         185 :         while (iface->ap_list) {
     263          92 :                 ap = iface->ap_list->prev;
     264          92 :                 if (!os_reltime_expired(&now, &ap->last_beacon,
     265          92 :                                         iface->conf->ap_table_expiration_time))
     266          91 :                         break;
     267             : 
     268           1 :                 ap_free_ap(iface, ap);
     269             :         }
     270             : 
     271          92 :         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          92 :         if (set_beacon)
     299           1 :                 ieee802_11_update_beacons(iface);
     300             : }
     301             : 
     302             : 
     303        2000 : int ap_list_init(struct hostapd_iface *iface)
     304             : {
     305        2000 :         return 0;
     306             : }
     307             : 
     308             : 
     309        2235 : void ap_list_deinit(struct hostapd_iface *iface)
     310             : {
     311        2235 :         hostapd_free_aps(iface);
     312        2235 : }

Generated by: LCOV version 1.10