ap_list.c

Go to the documentation of this file.
00001 
00019 #include "includes.h"
00020 
00021 #include "hostapd.h"
00022 #include "config.h"
00023 #include "ieee802_11.h"
00024 #include "eloop.h"
00025 #include "sta_info.h"
00026 #include "ap_list.h"
00027 #include "hw_features.h"
00028 #include "beacon.h"
00029 #include "drivers/driver.h"
00030 
00031 
00032 struct ieee80211_frame_info {
00033         u32 version;
00034         u32 length;
00035         u64 mactime;
00036         u64 hosttime;
00037         u32 phytype;
00038         u32 channel;
00039         u32 datarate;
00040         u32 antenna;
00041         u32 priority;
00042         u32 ssi_type;
00043         u32 ssi_signal;
00044         u32 ssi_noise;
00045         u32 preamble;
00046         u32 encoding;
00047 
00048         /* Note: this structure is otherwise identical to capture format used
00049          * in linux-wlan-ng, but this additional field is used to provide meta
00050          * data about the frame to hostapd. This was the easiest method for
00051          * providing this information, but this might change in the future. */
00052         u32 msg_type;
00053 } __attribute__ ((packed));
00054 
00055 
00056 enum ieee80211_phytype {
00057         ieee80211_phytype_fhss_dot11_97  = 1,
00058         ieee80211_phytype_dsss_dot11_97  = 2,
00059         ieee80211_phytype_irbaseband     = 3,
00060         ieee80211_phytype_dsss_dot11_b   = 4,
00061         ieee80211_phytype_pbcc_dot11_b   = 5,
00062         ieee80211_phytype_ofdm_dot11_g   = 6,
00063         ieee80211_phytype_pbcc_dot11_g   = 7,
00064         ieee80211_phytype_ofdm_dot11_a   = 8,
00065         ieee80211_phytype_dsss_dot11_turbog = 255,
00066         ieee80211_phytype_dsss_dot11_turbo = 256,
00067 };
00068 
00069 
00070 /* AP list is a double linked list with head->prev pointing to the end of the
00071  * list and tail->next = NULL. Entries are moved to the head of the list
00072  * whenever a beacon has been received from the AP in question. The tail entry
00073  * in this link will thus be the least recently used entry. */
00074 
00075 
00076 static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
00077 {
00078         int i;
00079 
00080         if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
00081             ap->phytype != ieee80211_phytype_pbcc_dot11_g ||
00082             iface->conf->channel != ap->channel)
00083                 return 0;
00084 
00085         if (ap->erp != -1 && (ap->erp & ERP_INFO_NON_ERP_PRESENT))
00086                 return 1;
00087 
00088         for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
00089                 int rate = (ap->supported_rates[i] & 0x7f) * 5;
00090                 if (rate == 60 || rate == 90 || rate > 110)
00091                         return 0;
00092         }
00093 
00094         return 1;
00095 }
00096 
00097 
00098 #ifdef CONFIG_IEEE80211N
00099 static int ap_list_beacon_olbc_ht(struct hostapd_iface *iface,
00100                                   struct ap_info *ap)
00101 {
00102         return !ap->ht_support;
00103 }
00104 #endif /* CONFIG_IEEE80211N */
00105 
00106 
00107 struct ap_info * ap_get_ap(struct hostapd_iface *iface, u8 *ap)
00108 {
00109         struct ap_info *s;
00110 
00111         s = iface->ap_hash[STA_HASH(ap)];
00112         while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0)
00113                 s = s->hnext;
00114         return s;
00115 }
00116 
00117 
00118 static void ap_ap_list_add(struct hostapd_iface *iface, struct ap_info *ap)
00119 {
00120         if (iface->ap_list) {
00121                 ap->prev = iface->ap_list->prev;
00122                 iface->ap_list->prev = ap;
00123         } else
00124                 ap->prev = ap;
00125         ap->next = iface->ap_list;
00126         iface->ap_list = ap;
00127 }
00128 
00129 
00130 static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap)
00131 {
00132         if (iface->ap_list == ap)
00133                 iface->ap_list = ap->next;
00134         else
00135                 ap->prev->next = ap->next;
00136 
00137         if (ap->next)
00138                 ap->next->prev = ap->prev;
00139         else if (iface->ap_list)
00140                 iface->ap_list->prev = ap->prev;
00141 }
00142 
00143 
00144 static void ap_ap_iter_list_add(struct hostapd_iface *iface,
00145                                 struct ap_info *ap)
00146 {
00147         if (iface->ap_iter_list) {
00148                 ap->iter_prev = iface->ap_iter_list->iter_prev;
00149                 iface->ap_iter_list->iter_prev = ap;
00150         } else
00151                 ap->iter_prev = ap;
00152         ap->iter_next = iface->ap_iter_list;
00153         iface->ap_iter_list = ap;
00154 }
00155 
00156 
00157 static void ap_ap_iter_list_del(struct hostapd_iface *iface,
00158                                 struct ap_info *ap)
00159 {
00160         if (iface->ap_iter_list == ap)
00161                 iface->ap_iter_list = ap->iter_next;
00162         else
00163                 ap->iter_prev->iter_next = ap->iter_next;
00164 
00165         if (ap->iter_next)
00166                 ap->iter_next->iter_prev = ap->iter_prev;
00167         else if (iface->ap_iter_list)
00168                 iface->ap_iter_list->iter_prev = ap->iter_prev;
00169 }
00170 
00171 
00172 static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
00173 {
00174         ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
00175         iface->ap_hash[STA_HASH(ap->addr)] = ap;
00176 }
00177 
00178 
00179 static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap)
00180 {
00181         struct ap_info *s;
00182 
00183         s = iface->ap_hash[STA_HASH(ap->addr)];
00184         if (s == NULL) return;
00185         if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) {
00186                 iface->ap_hash[STA_HASH(ap->addr)] = s->hnext;
00187                 return;
00188         }
00189 
00190         while (s->hnext != NULL &&
00191                os_memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0)
00192                 s = s->hnext;
00193         if (s->hnext != NULL)
00194                 s->hnext = s->hnext->hnext;
00195         else
00196                 printf("AP: could not remove AP " MACSTR " from hash table\n",
00197                        MAC2STR(ap->addr));
00198 }
00199 
00200 
00201 static void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap)
00202 {
00203         ap_ap_hash_del(iface, ap);
00204         ap_ap_list_del(iface, ap);
00205         ap_ap_iter_list_del(iface, ap);
00206 
00207         iface->num_ap--;
00208         os_free(ap);
00209 }
00210 
00211 
00212 static void hostapd_free_aps(struct hostapd_iface *iface)
00213 {
00214         struct ap_info *ap, *prev;
00215 
00216         ap = iface->ap_list;
00217 
00218         while (ap) {
00219                 prev = ap;
00220                 ap = ap->next;
00221                 ap_free_ap(iface, prev);
00222         }
00223 
00224         iface->ap_list = NULL;
00225 }
00226 
00227 
00228 int ap_ap_for_each(struct hostapd_iface *iface,
00229                    int (*func)(struct ap_info *s, void *data), void *data)
00230 {
00231         struct ap_info *s;
00232         int ret = 0;
00233 
00234         s = iface->ap_list;
00235 
00236         while (s) {
00237                 ret = func(s, data);
00238                 if (ret)
00239                         break;
00240                 s = s->next;
00241         }
00242 
00243         return ret;
00244 }
00245 
00246 
00247 static struct ap_info * ap_ap_add(struct hostapd_iface *iface, u8 *addr)
00248 {
00249         struct ap_info *ap;
00250 
00251         ap = os_zalloc(sizeof(struct ap_info));
00252         if (ap == NULL)
00253                 return NULL;
00254 
00255         /* initialize AP info data */
00256         os_memcpy(ap->addr, addr, ETH_ALEN);
00257         ap_ap_list_add(iface, ap);
00258         iface->num_ap++;
00259         ap_ap_hash_add(iface, ap);
00260         ap_ap_iter_list_add(iface, ap);
00261 
00262         if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) {
00263                 wpa_printf(MSG_DEBUG, "Removing the least recently used AP "
00264                            MACSTR " from AP table", MAC2STR(ap->prev->addr));
00265                 ap_free_ap(iface, ap->prev);
00266         }
00267 
00268         return ap;
00269 }
00270 
00271 
00272 void ap_list_process_beacon(struct hostapd_iface *iface,
00273                             struct ieee80211_mgmt *mgmt,
00274                             struct ieee802_11_elems *elems,
00275                             struct hostapd_frame_info *fi)
00276 {
00277         struct ap_info *ap;
00278         int new_ap = 0;
00279         size_t len;
00280         int set_beacon = 0;
00281 
00282         if (iface->conf->ap_table_max_size < 1)
00283                 return;
00284 
00285         ap = ap_get_ap(iface, mgmt->bssid);
00286         if (!ap) {
00287                 ap = ap_ap_add(iface, mgmt->bssid);
00288                 if (!ap) {
00289                         printf("Failed to allocate AP information entry\n");
00290                         return;
00291                 }
00292                 new_ap = 1;
00293         }
00294 
00295         ap->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int);
00296         ap->capability = le_to_host16(mgmt->u.beacon.capab_info);
00297 
00298         if (elems->ssid) {
00299                 len = elems->ssid_len;
00300                 if (len >= sizeof(ap->ssid))
00301                         len = sizeof(ap->ssid) - 1;
00302                 os_memcpy(ap->ssid, elems->ssid, len);
00303                 ap->ssid[len] = '\0';
00304                 ap->ssid_len = len;
00305         }
00306 
00307         os_memset(ap->supported_rates, 0, WLAN_SUPP_RATES_MAX);
00308         len = 0;
00309         if (elems->supp_rates) {
00310                 len = elems->supp_rates_len;
00311                 if (len > WLAN_SUPP_RATES_MAX)
00312                         len = WLAN_SUPP_RATES_MAX;
00313                 os_memcpy(ap->supported_rates, elems->supp_rates, len);
00314         }
00315         if (elems->ext_supp_rates) {
00316                 int len2;
00317                 if (len + elems->ext_supp_rates_len > WLAN_SUPP_RATES_MAX)
00318                         len2 = WLAN_SUPP_RATES_MAX - len;
00319                 else
00320                         len2 = elems->ext_supp_rates_len;
00321                 os_memcpy(ap->supported_rates + len, elems->ext_supp_rates,
00322                           len2);
00323         }
00324 
00325         ap->wpa = elems->wpa_ie != NULL;
00326 
00327         if (elems->erp_info && elems->erp_info_len == 1)
00328                 ap->erp = elems->erp_info[0];
00329         else
00330                 ap->erp = -1;
00331 
00332         if (elems->ds_params && elems->ds_params_len == 1)
00333                 ap->channel = elems->ds_params[0];
00334         else if (fi)
00335                 ap->channel = fi->channel;
00336 
00337         if (elems->ht_capabilities)
00338                 ap->ht_support = 1;
00339         else
00340                 ap->ht_support = 0;
00341 
00342         ap->num_beacons++;
00343         time(&ap->last_beacon);
00344         if (fi) {
00345                 ap->phytype = fi->phytype;
00346                 ap->ssi_signal = fi->ssi_signal;
00347                 ap->datarate = fi->datarate;
00348         }
00349 
00350         if (!new_ap && ap != iface->ap_list) {
00351                 /* move AP entry into the beginning of the list so that the
00352                  * oldest entry is always in the end of the list */
00353                 ap_ap_list_del(iface, ap);
00354                 ap_ap_list_add(iface, ap);
00355         }
00356 
00357         if (!iface->olbc &&
00358             ap_list_beacon_olbc(iface, ap)) {
00359                 iface->olbc = 1;
00360                 wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR " - enable "
00361                            "protection", MAC2STR(ap->addr));
00362                 set_beacon++;
00363         }
00364 
00365 #ifdef CONFIG_IEEE80211N
00366         if (!iface->olbc_ht && ap_list_beacon_olbc_ht(iface, ap)) {
00367                 iface->olbc_ht = 1;
00368                 hostapd_ht_operation_update(iface);
00369                 wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR
00370                            " - enable protection", MAC2STR(ap->addr));
00371                 set_beacon++;
00372         }
00373 #endif /* CONFIG_IEEE80211N */
00374 
00375         if (set_beacon)
00376                 ieee802_11_set_beacons(iface);
00377 }
00378 
00379 
00380 static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
00381 {
00382         struct hostapd_iface *iface = eloop_ctx;
00383         time_t now;
00384         struct ap_info *ap;
00385         int set_beacon = 0;
00386 
00387         eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
00388 
00389         if (!iface->ap_list)
00390                 return;
00391 
00392         time(&now);
00393 
00394         while (iface->ap_list) {
00395                 ap = iface->ap_list->prev;
00396                 if (ap->last_beacon + iface->conf->ap_table_expiration_time >=
00397                     now)
00398                         break;
00399 
00400                 ap_free_ap(iface, ap);
00401         }
00402 
00403         if (iface->olbc || iface->olbc_ht) {
00404                 int olbc = 0;
00405                 int olbc_ht = 0;
00406 
00407                 ap = iface->ap_list;
00408                 while (ap && (olbc == 0 || olbc_ht == 0)) {
00409                         if (ap_list_beacon_olbc(iface, ap))
00410                                 olbc = 1;
00411 #ifdef CONFIG_IEEE80211N
00412                         if (ap_list_beacon_olbc_ht(iface, ap))
00413                                 olbc_ht = 1;
00414 #endif /* CONFIG_IEEE80211N */
00415                         ap = ap->next;
00416                 }
00417                 if (!olbc && iface->olbc) {
00418                         wpa_printf(MSG_DEBUG, "OLBC not detected anymore");
00419                         iface->olbc = 0;
00420                         set_beacon++;
00421                 }
00422 #ifdef CONFIG_IEEE80211N
00423                 if (!olbc_ht && iface->olbc_ht) {
00424                         wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore");
00425                         iface->olbc_ht = 0;
00426                         hostapd_ht_operation_update(iface);
00427                         set_beacon++;
00428                 }
00429 #endif /* CONFIG_IEEE80211N */
00430         }
00431 
00432         if (set_beacon)
00433                 ieee802_11_set_beacons(iface);
00434 }
00435 
00436 
00437 int ap_list_init(struct hostapd_iface *iface)
00438 {
00439         eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
00440         return 0;
00441 }
00442 
00443 
00444 void ap_list_deinit(struct hostapd_iface *iface)
00445 {
00446         eloop_cancel_timeout(ap_list_timer, iface, NULL);
00447         hostapd_free_aps(iface);
00448 }
00449 
00450 
00451 int ap_list_reconfig(struct hostapd_iface *iface,
00452                      struct hostapd_config *oldconf)
00453 {
00454         time_t now;
00455         struct ap_info *ap;
00456 
00457         if (iface->conf->ap_table_max_size == oldconf->ap_table_max_size &&
00458             iface->conf->ap_table_expiration_time ==
00459             oldconf->ap_table_expiration_time)
00460                 return 0;
00461 
00462         time(&now);
00463 
00464         while (iface->ap_list) {
00465                 ap = iface->ap_list->prev;
00466                 if (iface->num_ap <= iface->conf->ap_table_max_size &&
00467                     ap->last_beacon + iface->conf->ap_table_expiration_time >=
00468                     now)
00469                         break;
00470 
00471                 ap_free_ap(iface, iface->ap_list->prev);
00472         }
00473 
00474         return 0;
00475 }
00476 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on Sat Nov 21 23:16:47 2009 for hostapd by  doxygen 1.6.1