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 1422976643 Lines: 155 168 92.3 %
Date: 2015-02-03 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        7480 : static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
      32             : {
      33             :         int i;
      34             : 
      35       14960 :         if (iface->current_mode == NULL ||
      36       14929 :             iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
      37        7449 :             iface->conf->channel != ap->channel)
      38          51 :                 return 0;
      39             : 
      40        7429 :         if (ap->erp != -1 && (ap->erp & ERP_INFO_NON_ERP_PRESENT))
      41           0 :                 return 1;
      42             : 
      43       36049 :         for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
      44       36048 :                 int rate = (ap->supported_rates[i] & 0x7f) * 5;
      45       36048 :                 if (rate == 60 || rate == 90 || rate > 110)
      46        7428 :                         return 0;
      47             :         }
      48             : 
      49           1 :         return 1;
      50             : }
      51             : 
      52             : 
      53        7486 : static struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
      54             : {
      55             :         struct ap_info *s;
      56             : 
      57        7486 :         s = iface->ap_hash[STA_HASH(ap)];
      58       14981 :         while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0)
      59           9 :                 s = s->hnext;
      60        7486 :         return s;
      61             : }
      62             : 
      63             : 
      64         270 : static void ap_ap_list_add(struct hostapd_iface *iface, struct ap_info *ap)
      65             : {
      66         270 :         if (iface->ap_list) {
      67          33 :                 ap->prev = iface->ap_list->prev;
      68          33 :                 iface->ap_list->prev = ap;
      69             :         } else
      70         237 :                 ap->prev = ap;
      71         270 :         ap->next = iface->ap_list;
      72         270 :         iface->ap_list = ap;
      73         270 : }
      74             : 
      75             : 
      76         270 : static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap)
      77             : {
      78         270 :         if (iface->ap_list == ap)
      79         243 :                 iface->ap_list = ap->next;
      80             :         else
      81          27 :                 ap->prev->next = ap->next;
      82             : 
      83         270 :         if (ap->next)
      84           6 :                 ap->next->prev = ap->prev;
      85         264 :         else if (iface->ap_list)
      86          27 :                 iface->ap_list->prev = ap->prev;
      87         270 : }
      88             : 
      89             : 
      90         265 : static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
      91             : {
      92         265 :         ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
      93         265 :         iface->ap_hash[STA_HASH(ap->addr)] = ap;
      94         265 : }
      95             : 
      96             : 
      97         265 : static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap)
      98             : {
      99             :         struct ap_info *s;
     100             : 
     101         265 :         s = iface->ap_hash[STA_HASH(ap->addr)];
     102         265 :         if (s == NULL) return;
     103         265 :         if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) {
     104         262 :                 iface->ap_hash[STA_HASH(ap->addr)] = s->hnext;
     105         262 :                 return;
     106             :         }
     107             : 
     108           9 :         while (s->hnext != NULL &&
     109           3 :                os_memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0)
     110           0 :                 s = s->hnext;
     111           3 :         if (s->hnext != NULL)
     112           3 :                 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         265 : static void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap)
     120             : {
     121         265 :         ap_ap_hash_del(iface, ap);
     122         265 :         ap_ap_list_del(iface, ap);
     123             : 
     124         265 :         iface->num_ap--;
     125         265 :         os_free(ap);
     126         265 : }
     127             : 
     128             : 
     129        1395 : static void hostapd_free_aps(struct hostapd_iface *iface)
     130             : {
     131             :         struct ap_info *ap, *prev;
     132             : 
     133        1395 :         ap = iface->ap_list;
     134             : 
     135        3032 :         while (ap) {
     136         242 :                 prev = ap;
     137         242 :                 ap = ap->next;
     138         242 :                 ap_free_ap(iface, prev);
     139             :         }
     140             : 
     141        1395 :         iface->ap_list = NULL;
     142        1395 : }
     143             : 
     144             : 
     145         266 : static struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr)
     146             : {
     147             :         struct ap_info *ap;
     148             : 
     149         266 :         ap = os_zalloc(sizeof(struct ap_info));
     150         266 :         if (ap == NULL)
     151           1 :                 return NULL;
     152             : 
     153             :         /* initialize AP info data */
     154         265 :         os_memcpy(ap->addr, addr, ETH_ALEN);
     155         265 :         ap_ap_list_add(iface, ap);
     156         265 :         iface->num_ap++;
     157         265 :         ap_ap_hash_add(iface, ap);
     158             : 
     159         265 :         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         265 :         return ap;
     166             : }
     167             : 
     168             : 
     169        7500 : 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        7500 :         int new_ap = 0;
     176        7500 :         int set_beacon = 0;
     177             : 
     178        7500 :         if (iface->conf->ap_table_max_size < 1)
     179          14 :                 return;
     180             : 
     181        7486 :         ap = ap_get_ap(iface, mgmt->bssid);
     182        7486 :         if (!ap) {
     183         266 :                 ap = ap_ap_add(iface, mgmt->bssid);
     184         266 :                 if (!ap) {
     185           1 :                         wpa_printf(MSG_INFO,
     186             :                                    "Failed to allocate AP information entry");
     187           1 :                         return;
     188             :                 }
     189         265 :                 new_ap = 1;
     190             :         }
     191             : 
     192       14970 :         merge_byte_arrays(ap->supported_rates, WLAN_SUPP_RATES_MAX,
     193        7485 :                           elems->supp_rates, elems->supp_rates_len,
     194        7485 :                           elems->ext_supp_rates, elems->ext_supp_rates_len);
     195             : 
     196        7485 :         if (elems->erp_info && elems->erp_info_len == 1)
     197        7453 :                 ap->erp = elems->erp_info[0];
     198             :         else
     199          32 :                 ap->erp = -1;
     200             : 
     201        7485 :         if (elems->ds_params && elems->ds_params_len == 1)
     202        7485 :                 ap->channel = elems->ds_params[0];
     203           0 :         else if (elems->ht_operation && elems->ht_operation_len >= 1)
     204           0 :                 ap->channel = elems->ht_operation[0];
     205           0 :         else if (fi)
     206           0 :                 ap->channel = fi->channel;
     207             : 
     208        7485 :         if (elems->ht_capabilities)
     209        7477 :                 ap->ht_support = 1;
     210             :         else
     211           8 :                 ap->ht_support = 0;
     212             : 
     213        7485 :         os_get_reltime(&ap->last_beacon);
     214             : 
     215        7485 :         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           5 :                 ap_ap_list_del(iface, ap);
     219           5 :                 ap_ap_list_add(iface, ap);
     220             :         }
     221             : 
     222       14965 :         if (!iface->olbc &&
     223        7480 :             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        7488 :         if (!iface->olbc_ht && !ap->ht_support &&
     233           6 :             (ap->channel == 0 ||
     234           4 :              ap->channel == iface->conf->channel ||
     235           2 :              ap->channel == iface->conf->channel +
     236           1 :              iface->conf->secondary_channel * 4)) {
     237           2 :                 iface->olbc_ht = 1;
     238           2 :                 hostapd_ht_operation_update(iface);
     239          14 :                 wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR
     240             :                            " (channel %d) - enable protection",
     241          12 :                            MAC2STR(ap->addr), ap->channel);
     242           2 :                 set_beacon++;
     243             :         }
     244             : #endif /* CONFIG_IEEE80211N */
     245             : 
     246        7485 :         if (set_beacon)
     247           2 :                 ieee802_11_update_beacons(iface);
     248             : }
     249             : 
     250             : 
     251         986 : static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
     252             : {
     253         986 :         struct hostapd_iface *iface = eloop_ctx;
     254             :         struct os_reltime now;
     255             :         struct ap_info *ap;
     256         986 :         int set_beacon = 0;
     257             : 
     258         986 :         eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
     259             : 
     260         986 :         if (!iface->ap_list)
     261        1928 :                 return;
     262             : 
     263          44 :         os_get_reltime(&now);
     264             : 
     265          89 :         while (iface->ap_list) {
     266          44 :                 ap = iface->ap_list->prev;
     267          44 :                 if (!os_reltime_expired(&now, &ap->last_beacon,
     268          44 :                                         iface->conf->ap_table_expiration_time))
     269          43 :                         break;
     270             : 
     271           1 :                 ap_free_ap(iface, ap);
     272             :         }
     273             : 
     274          44 :         if (iface->olbc || iface->olbc_ht) {
     275           1 :                 int olbc = 0;
     276           1 :                 int olbc_ht = 0;
     277             : 
     278           1 :                 ap = iface->ap_list;
     279           2 :                 while (ap && (olbc == 0 || olbc_ht == 0)) {
     280           0 :                         if (ap_list_beacon_olbc(iface, ap))
     281           0 :                                 olbc = 1;
     282           0 :                         if (!ap->ht_support)
     283           0 :                                 olbc_ht = 1;
     284           0 :                         ap = ap->next;
     285             :                 }
     286           1 :                 if (!olbc && iface->olbc) {
     287           1 :                         wpa_printf(MSG_DEBUG, "OLBC not detected anymore");
     288           1 :                         iface->olbc = 0;
     289           1 :                         set_beacon++;
     290             :                 }
     291             : #ifdef CONFIG_IEEE80211N
     292           1 :                 if (!olbc_ht && iface->olbc_ht) {
     293           1 :                         wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore");
     294           1 :                         iface->olbc_ht = 0;
     295           1 :                         hostapd_ht_operation_update(iface);
     296           1 :                         set_beacon++;
     297             :                 }
     298             : #endif /* CONFIG_IEEE80211N */
     299             :         }
     300             : 
     301          44 :         if (set_beacon)
     302           1 :                 ieee802_11_update_beacons(iface);
     303             : }
     304             : 
     305             : 
     306        1202 : int ap_list_init(struct hostapd_iface *iface)
     307             : {
     308        1202 :         eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
     309        1202 :         return 0;
     310             : }
     311             : 
     312             : 
     313        1395 : void ap_list_deinit(struct hostapd_iface *iface)
     314             : {
     315        1395 :         eloop_cancel_timeout(ap_list_timer, iface, NULL);
     316        1395 :         hostapd_free_aps(iface);
     317        1395 : }

Generated by: LCOV version 1.10