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 1401264779 Lines: 147 168 87.5 %
Date: 2014-05-28 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        1851 : static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
      32             : {
      33             :         int i;
      34             : 
      35        3702 :         if (iface->current_mode == NULL ||
      36        3660 :             iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
      37        1809 :             iface->conf->channel != ap->channel)
      38          44 :                 return 0;
      39             : 
      40        1807 :         if (ap->erp != -1 && (ap->erp & ERP_INFO_NON_ERP_PRESENT))
      41           0 :                 return 1;
      42             : 
      43        8211 :         for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
      44        8210 :                 int rate = (ap->supported_rates[i] & 0x7f) * 5;
      45        8210 :                 if (rate == 60 || rate == 90 || rate > 110)
      46        1806 :                         return 0;
      47             :         }
      48             : 
      49           1 :         return 1;
      50             : }
      51             : 
      52             : 
      53        1855 : static struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
      54             : {
      55             :         struct ap_info *s;
      56             : 
      57        1855 :         s = iface->ap_hash[STA_HASH(ap)];
      58        3715 :         while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0)
      59           5 :                 s = s->hnext;
      60        1855 :         return s;
      61             : }
      62             : 
      63             : 
      64         151 : static void ap_ap_list_add(struct hostapd_iface *iface, struct ap_info *ap)
      65             : {
      66         151 :         if (iface->ap_list) {
      67           2 :                 ap->prev = iface->ap_list->prev;
      68           2 :                 iface->ap_list->prev = ap;
      69             :         } else
      70         149 :                 ap->prev = ap;
      71         151 :         ap->next = iface->ap_list;
      72         151 :         iface->ap_list = ap;
      73         151 : }
      74             : 
      75             : 
      76         151 : static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap)
      77             : {
      78         151 :         if (iface->ap_list == ap)
      79         150 :                 iface->ap_list = ap->next;
      80             :         else
      81           1 :                 ap->prev->next = ap->next;
      82             : 
      83         151 :         if (ap->next)
      84           1 :                 ap->next->prev = ap->prev;
      85         150 :         else if (iface->ap_list)
      86           1 :                 iface->ap_list->prev = ap->prev;
      87         151 : }
      88             : 
      89             : 
      90         150 : static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
      91             : {
      92         150 :         ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
      93         150 :         iface->ap_hash[STA_HASH(ap->addr)] = ap;
      94         150 : }
      95             : 
      96             : 
      97         150 : static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap)
      98             : {
      99             :         struct ap_info *s;
     100             : 
     101         150 :         s = iface->ap_hash[STA_HASH(ap->addr)];
     102         150 :         if (s == NULL) return;
     103         150 :         if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) {
     104         149 :                 iface->ap_hash[STA_HASH(ap->addr)] = s->hnext;
     105         149 :                 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 :                 printf("AP: could not remove AP " MACSTR " from hash table\n",
     115           0 :                        MAC2STR(ap->addr));
     116             : }
     117             : 
     118             : 
     119         150 : static void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap)
     120             : {
     121         150 :         ap_ap_hash_del(iface, ap);
     122         150 :         ap_ap_list_del(iface, ap);
     123             : 
     124         150 :         iface->num_ap--;
     125         150 :         os_free(ap);
     126         150 : }
     127             : 
     128             : 
     129         691 : static void hostapd_free_aps(struct hostapd_iface *iface)
     130             : {
     131             :         struct ap_info *ap, *prev;
     132             : 
     133         691 :         ap = iface->ap_list;
     134             : 
     135        1531 :         while (ap) {
     136         149 :                 prev = ap;
     137         149 :                 ap = ap->next;
     138         149 :                 ap_free_ap(iface, prev);
     139             :         }
     140             : 
     141         691 :         iface->ap_list = NULL;
     142         691 : }
     143             : 
     144             : 
     145         150 : static struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr)
     146             : {
     147             :         struct ap_info *ap;
     148             : 
     149         150 :         ap = os_zalloc(sizeof(struct ap_info));
     150         150 :         if (ap == NULL)
     151           0 :                 return NULL;
     152             : 
     153             :         /* initialize AP info data */
     154         150 :         os_memcpy(ap->addr, addr, ETH_ALEN);
     155         150 :         ap_ap_list_add(iface, ap);
     156         150 :         iface->num_ap++;
     157         150 :         ap_ap_hash_add(iface, ap);
     158             : 
     159         150 :         if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) {
     160           0 :                 wpa_printf(MSG_DEBUG, "Removing the least recently used AP "
     161           0 :                            MACSTR " from AP table", MAC2STR(ap->prev->addr));
     162           0 :                 ap_free_ap(iface, ap->prev);
     163             :         }
     164             : 
     165         150 :         return ap;
     166             : }
     167             : 
     168             : 
     169        1855 : 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        1855 :         int new_ap = 0;
     176        1855 :         int set_beacon = 0;
     177             : 
     178        1855 :         if (iface->conf->ap_table_max_size < 1)
     179           0 :                 return;
     180             : 
     181        1855 :         ap = ap_get_ap(iface, mgmt->bssid);
     182        1855 :         if (!ap) {
     183         150 :                 ap = ap_ap_add(iface, mgmt->bssid);
     184         150 :                 if (!ap) {
     185           0 :                         printf("Failed to allocate AP information entry\n");
     186           0 :                         return;
     187             :                 }
     188         150 :                 new_ap = 1;
     189             :         }
     190             : 
     191        3710 :         merge_byte_arrays(ap->supported_rates, WLAN_SUPP_RATES_MAX,
     192        1855 :                           elems->supp_rates, elems->supp_rates_len,
     193        1855 :                           elems->ext_supp_rates, elems->ext_supp_rates_len);
     194             : 
     195        1855 :         if (elems->erp_info && elems->erp_info_len == 1)
     196        1813 :                 ap->erp = elems->erp_info[0];
     197             :         else
     198          42 :                 ap->erp = -1;
     199             : 
     200        1855 :         if (elems->ds_params && elems->ds_params_len == 1)
     201        1855 :                 ap->channel = elems->ds_params[0];
     202           0 :         else if (elems->ht_operation && elems->ht_operation_len >= 1)
     203           0 :                 ap->channel = elems->ht_operation[0];
     204           0 :         else if (fi)
     205           0 :                 ap->channel = fi->channel;
     206             : 
     207        1855 :         if (elems->ht_capabilities)
     208        1843 :                 ap->ht_support = 1;
     209             :         else
     210          12 :                 ap->ht_support = 0;
     211             : 
     212        1855 :         os_get_reltime(&ap->last_beacon);
     213             : 
     214        1855 :         if (!new_ap && ap != iface->ap_list) {
     215             :                 /* move AP entry into the beginning of the list so that the
     216             :                  * oldest entry is always in the end of the list */
     217           1 :                 ap_ap_list_del(iface, ap);
     218           1 :                 ap_ap_list_add(iface, ap);
     219             :         }
     220             : 
     221        3706 :         if (!iface->olbc &&
     222        1851 :             ap_list_beacon_olbc(iface, ap)) {
     223           1 :                 iface->olbc = 1;
     224           7 :                 wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR
     225             :                            " (channel %d) - enable protection",
     226           6 :                            MAC2STR(ap->addr), ap->channel);
     227           1 :                 set_beacon++;
     228             :         }
     229             : 
     230             : #ifdef CONFIG_IEEE80211N
     231        1858 :         if (!iface->olbc_ht && !ap->ht_support &&
     232           6 :             (ap->channel == 0 ||
     233           4 :              ap->channel == iface->conf->channel ||
     234           2 :              ap->channel == iface->conf->channel +
     235           1 :              iface->conf->secondary_channel * 4)) {
     236           2 :                 iface->olbc_ht = 1;
     237           2 :                 hostapd_ht_operation_update(iface);
     238          14 :                 wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR
     239             :                            " (channel %d) - enable protection",
     240          12 :                            MAC2STR(ap->addr), ap->channel);
     241           2 :                 set_beacon++;
     242             :         }
     243             : #endif /* CONFIG_IEEE80211N */
     244             : 
     245        1855 :         if (set_beacon)
     246           2 :                 ieee802_11_update_beacons(iface);
     247             : }
     248             : 
     249             : 
     250         531 : static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
     251             : {
     252         531 :         struct hostapd_iface *iface = eloop_ctx;
     253             :         struct os_reltime now;
     254             :         struct ap_info *ap;
     255         531 :         int set_beacon = 0;
     256             : 
     257         531 :         eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
     258             : 
     259         531 :         if (!iface->ap_list)
     260        1061 :                 return;
     261             : 
     262           1 :         os_get_reltime(&now);
     263             : 
     264           3 :         while (iface->ap_list) {
     265           1 :                 ap = iface->ap_list->prev;
     266           1 :                 if (!os_reltime_expired(&now, &ap->last_beacon,
     267           1 :                                         iface->conf->ap_table_expiration_time))
     268           0 :                         break;
     269             : 
     270           1 :                 ap_free_ap(iface, ap);
     271             :         }
     272             : 
     273           1 :         if (iface->olbc || iface->olbc_ht) {
     274           1 :                 int olbc = 0;
     275           1 :                 int olbc_ht = 0;
     276             : 
     277           1 :                 ap = iface->ap_list;
     278           2 :                 while (ap && (olbc == 0 || olbc_ht == 0)) {
     279           0 :                         if (ap_list_beacon_olbc(iface, ap))
     280           0 :                                 olbc = 1;
     281           0 :                         if (!ap->ht_support)
     282           0 :                                 olbc_ht = 1;
     283           0 :                         ap = ap->next;
     284             :                 }
     285           1 :                 if (!olbc && iface->olbc) {
     286           1 :                         wpa_printf(MSG_DEBUG, "OLBC not detected anymore");
     287           1 :                         iface->olbc = 0;
     288           1 :                         set_beacon++;
     289             :                 }
     290             : #ifdef CONFIG_IEEE80211N
     291           1 :                 if (!olbc_ht && iface->olbc_ht) {
     292           1 :                         wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore");
     293           1 :                         iface->olbc_ht = 0;
     294           1 :                         hostapd_ht_operation_update(iface);
     295           1 :                         set_beacon++;
     296             :                 }
     297             : #endif /* CONFIG_IEEE80211N */
     298             :         }
     299             : 
     300           1 :         if (set_beacon)
     301           1 :                 ieee802_11_update_beacons(iface);
     302             : }
     303             : 
     304             : 
     305         661 : int ap_list_init(struct hostapd_iface *iface)
     306             : {
     307         661 :         eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
     308         661 :         return 0;
     309             : }
     310             : 
     311             : 
     312         691 : void ap_list_deinit(struct hostapd_iface *iface)
     313             : {
     314         691 :         eloop_cancel_timeout(ap_list_timer, iface, NULL);
     315         691 :         hostapd_free_aps(iface);
     316         691 : }

Generated by: LCOV version 1.10