$search
00001 /* 00002 * hostapd / AP table 00003 * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> 00004 * Copyright (c) 2003-2004, Instant802 Networks, Inc. 00005 * Copyright (c) 2006, Devicescape Software, Inc. 00006 * 00007 * This program is free software; you can redistribute it and/or modify 00008 * it under the terms of the GNU General Public License version 2 as 00009 * published by the Free Software Foundation. 00010 * 00011 * Alternatively, this software may be distributed under the terms of BSD 00012 * license. 00013 * 00014 * See README and COPYING for more details. 00015 */ 00016 00017 #include "utils/includes.h" 00018 00019 #include "utils/common.h" 00020 #include "utils/eloop.h" 00021 #include "common/ieee802_11_defs.h" 00022 #include "common/ieee802_11_common.h" 00023 #include "drivers/driver.h" 00024 #include "hostapd.h" 00025 #include "ap_config.h" 00026 #include "ieee802_11.h" 00027 #include "sta_info.h" 00028 #include "beacon.h" 00029 #include "ap_list.h" 00030 00031 00032 /* AP list is a double linked list with head->prev pointing to the end of the 00033 * list and tail->next = NULL. Entries are moved to the head of the list 00034 * whenever a beacon has been received from the AP in question. The tail entry 00035 * in this link will thus be the least recently used entry. */ 00036 00037 00038 static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap) 00039 { 00040 int i; 00041 00042 if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G || 00043 iface->conf->channel != ap->channel) 00044 return 0; 00045 00046 if (ap->erp != -1 && (ap->erp & ERP_INFO_NON_ERP_PRESENT)) 00047 return 1; 00048 00049 for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) { 00050 int rate = (ap->supported_rates[i] & 0x7f) * 5; 00051 if (rate == 60 || rate == 90 || rate > 110) 00052 return 0; 00053 } 00054 00055 return 1; 00056 } 00057 00058 00059 struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap) 00060 { 00061 struct ap_info *s; 00062 00063 s = iface->ap_hash[STA_HASH(ap)]; 00064 while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0) 00065 s = s->hnext; 00066 return s; 00067 } 00068 00069 00070 static void ap_ap_list_add(struct hostapd_iface *iface, struct ap_info *ap) 00071 { 00072 if (iface->ap_list) { 00073 ap->prev = iface->ap_list->prev; 00074 iface->ap_list->prev = ap; 00075 } else 00076 ap->prev = ap; 00077 ap->next = iface->ap_list; 00078 iface->ap_list = ap; 00079 } 00080 00081 00082 static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap) 00083 { 00084 if (iface->ap_list == ap) 00085 iface->ap_list = ap->next; 00086 else 00087 ap->prev->next = ap->next; 00088 00089 if (ap->next) 00090 ap->next->prev = ap->prev; 00091 else if (iface->ap_list) 00092 iface->ap_list->prev = ap->prev; 00093 } 00094 00095 00096 static void ap_ap_iter_list_add(struct hostapd_iface *iface, 00097 struct ap_info *ap) 00098 { 00099 if (iface->ap_iter_list) { 00100 ap->iter_prev = iface->ap_iter_list->iter_prev; 00101 iface->ap_iter_list->iter_prev = ap; 00102 } else 00103 ap->iter_prev = ap; 00104 ap->iter_next = iface->ap_iter_list; 00105 iface->ap_iter_list = ap; 00106 } 00107 00108 00109 static void ap_ap_iter_list_del(struct hostapd_iface *iface, 00110 struct ap_info *ap) 00111 { 00112 if (iface->ap_iter_list == ap) 00113 iface->ap_iter_list = ap->iter_next; 00114 else 00115 ap->iter_prev->iter_next = ap->iter_next; 00116 00117 if (ap->iter_next) 00118 ap->iter_next->iter_prev = ap->iter_prev; 00119 else if (iface->ap_iter_list) 00120 iface->ap_iter_list->iter_prev = ap->iter_prev; 00121 } 00122 00123 00124 static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap) 00125 { 00126 ap->hnext = iface->ap_hash[STA_HASH(ap->addr)]; 00127 iface->ap_hash[STA_HASH(ap->addr)] = ap; 00128 } 00129 00130 00131 static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap) 00132 { 00133 struct ap_info *s; 00134 00135 s = iface->ap_hash[STA_HASH(ap->addr)]; 00136 if (s == NULL) return; 00137 if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) { 00138 iface->ap_hash[STA_HASH(ap->addr)] = s->hnext; 00139 return; 00140 } 00141 00142 while (s->hnext != NULL && 00143 os_memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0) 00144 s = s->hnext; 00145 if (s->hnext != NULL) 00146 s->hnext = s->hnext->hnext; 00147 else 00148 printf("AP: could not remove AP " MACSTR " from hash table\n", 00149 MAC2STR(ap->addr)); 00150 } 00151 00152 00153 static void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap) 00154 { 00155 ap_ap_hash_del(iface, ap); 00156 ap_ap_list_del(iface, ap); 00157 ap_ap_iter_list_del(iface, ap); 00158 00159 iface->num_ap--; 00160 os_free(ap); 00161 } 00162 00163 00164 static void hostapd_free_aps(struct hostapd_iface *iface) 00165 { 00166 struct ap_info *ap, *prev; 00167 00168 ap = iface->ap_list; 00169 00170 while (ap) { 00171 prev = ap; 00172 ap = ap->next; 00173 ap_free_ap(iface, prev); 00174 } 00175 00176 iface->ap_list = NULL; 00177 } 00178 00179 00180 int ap_ap_for_each(struct hostapd_iface *iface, 00181 int (*func)(struct ap_info *s, void *data), void *data) 00182 { 00183 struct ap_info *s; 00184 int ret = 0; 00185 00186 s = iface->ap_list; 00187 00188 while (s) { 00189 ret = func(s, data); 00190 if (ret) 00191 break; 00192 s = s->next; 00193 } 00194 00195 return ret; 00196 } 00197 00198 00199 static struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr) 00200 { 00201 struct ap_info *ap; 00202 00203 ap = os_zalloc(sizeof(struct ap_info)); 00204 if (ap == NULL) 00205 return NULL; 00206 00207 /* initialize AP info data */ 00208 os_memcpy(ap->addr, addr, ETH_ALEN); 00209 ap_ap_list_add(iface, ap); 00210 iface->num_ap++; 00211 ap_ap_hash_add(iface, ap); 00212 ap_ap_iter_list_add(iface, ap); 00213 00214 if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) { 00215 wpa_printf(MSG_DEBUG, "Removing the least recently used AP " 00216 MACSTR " from AP table", MAC2STR(ap->prev->addr)); 00217 ap_free_ap(iface, ap->prev); 00218 } 00219 00220 return ap; 00221 } 00222 00223 00224 void ap_list_process_beacon(struct hostapd_iface *iface, 00225 const struct ieee80211_mgmt *mgmt, 00226 struct ieee802_11_elems *elems, 00227 struct hostapd_frame_info *fi) 00228 { 00229 struct ap_info *ap; 00230 int new_ap = 0; 00231 size_t len; 00232 int set_beacon = 0; 00233 00234 if (iface->conf->ap_table_max_size < 1) 00235 return; 00236 00237 ap = ap_get_ap(iface, mgmt->bssid); 00238 if (!ap) { 00239 ap = ap_ap_add(iface, mgmt->bssid); 00240 if (!ap) { 00241 printf("Failed to allocate AP information entry\n"); 00242 return; 00243 } 00244 new_ap = 1; 00245 } 00246 00247 ap->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int); 00248 ap->capability = le_to_host16(mgmt->u.beacon.capab_info); 00249 00250 if (elems->ssid) { 00251 len = elems->ssid_len; 00252 if (len >= sizeof(ap->ssid)) 00253 len = sizeof(ap->ssid) - 1; 00254 os_memcpy(ap->ssid, elems->ssid, len); 00255 ap->ssid[len] = '\0'; 00256 ap->ssid_len = len; 00257 } 00258 00259 os_memset(ap->supported_rates, 0, WLAN_SUPP_RATES_MAX); 00260 len = 0; 00261 if (elems->supp_rates) { 00262 len = elems->supp_rates_len; 00263 if (len > WLAN_SUPP_RATES_MAX) 00264 len = WLAN_SUPP_RATES_MAX; 00265 os_memcpy(ap->supported_rates, elems->supp_rates, len); 00266 } 00267 if (elems->ext_supp_rates) { 00268 int len2; 00269 if (len + elems->ext_supp_rates_len > WLAN_SUPP_RATES_MAX) 00270 len2 = WLAN_SUPP_RATES_MAX - len; 00271 else 00272 len2 = elems->ext_supp_rates_len; 00273 os_memcpy(ap->supported_rates + len, elems->ext_supp_rates, 00274 len2); 00275 } 00276 00277 ap->wpa = elems->wpa_ie != NULL; 00278 00279 if (elems->erp_info && elems->erp_info_len == 1) 00280 ap->erp = elems->erp_info[0]; 00281 else 00282 ap->erp = -1; 00283 00284 if (elems->ds_params && elems->ds_params_len == 1) 00285 ap->channel = elems->ds_params[0]; 00286 else if (fi) 00287 ap->channel = fi->channel; 00288 00289 if (elems->ht_capabilities) 00290 ap->ht_support = 1; 00291 else 00292 ap->ht_support = 0; 00293 00294 ap->num_beacons++; 00295 time(&ap->last_beacon); 00296 if (fi) { 00297 ap->ssi_signal = fi->ssi_signal; 00298 ap->datarate = fi->datarate; 00299 } 00300 00301 if (!new_ap && ap != iface->ap_list) { 00302 /* move AP entry into the beginning of the list so that the 00303 * oldest entry is always in the end of the list */ 00304 ap_ap_list_del(iface, ap); 00305 ap_ap_list_add(iface, ap); 00306 } 00307 00308 if (!iface->olbc && 00309 ap_list_beacon_olbc(iface, ap)) { 00310 iface->olbc = 1; 00311 wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR " - enable " 00312 "protection", MAC2STR(ap->addr)); 00313 set_beacon++; 00314 } 00315 00316 #ifdef CONFIG_IEEE80211N 00317 if (!iface->olbc_ht && !ap->ht_support) { 00318 iface->olbc_ht = 1; 00319 hostapd_ht_operation_update(iface); 00320 wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR 00321 " - enable protection", MAC2STR(ap->addr)); 00322 set_beacon++; 00323 } 00324 #endif /* CONFIG_IEEE80211N */ 00325 00326 if (set_beacon) 00327 ieee802_11_set_beacons(iface); 00328 } 00329 00330 00331 static void ap_list_timer(void *eloop_ctx, void *timeout_ctx) 00332 { 00333 struct hostapd_iface *iface = eloop_ctx; 00334 time_t now; 00335 struct ap_info *ap; 00336 int set_beacon = 0; 00337 00338 eloop_register_timeout(10, 0, ap_list_timer, iface, NULL); 00339 00340 if (!iface->ap_list) 00341 return; 00342 00343 time(&now); 00344 00345 while (iface->ap_list) { 00346 ap = iface->ap_list->prev; 00347 if (ap->last_beacon + iface->conf->ap_table_expiration_time >= 00348 now) 00349 break; 00350 00351 ap_free_ap(iface, ap); 00352 } 00353 00354 if (iface->olbc || iface->olbc_ht) { 00355 int olbc = 0; 00356 int olbc_ht = 0; 00357 00358 ap = iface->ap_list; 00359 while (ap && (olbc == 0 || olbc_ht == 0)) { 00360 if (ap_list_beacon_olbc(iface, ap)) 00361 olbc = 1; 00362 if (!ap->ht_support) 00363 olbc_ht = 1; 00364 ap = ap->next; 00365 } 00366 if (!olbc && iface->olbc) { 00367 wpa_printf(MSG_DEBUG, "OLBC not detected anymore"); 00368 iface->olbc = 0; 00369 set_beacon++; 00370 } 00371 #ifdef CONFIG_IEEE80211N 00372 if (!olbc_ht && iface->olbc_ht) { 00373 wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore"); 00374 iface->olbc_ht = 0; 00375 hostapd_ht_operation_update(iface); 00376 set_beacon++; 00377 } 00378 #endif /* CONFIG_IEEE80211N */ 00379 } 00380 00381 if (set_beacon) 00382 ieee802_11_set_beacons(iface); 00383 } 00384 00385 00386 int ap_list_init(struct hostapd_iface *iface) 00387 { 00388 eloop_register_timeout(10, 0, ap_list_timer, iface, NULL); 00389 return 0; 00390 } 00391 00392 00393 void ap_list_deinit(struct hostapd_iface *iface) 00394 { 00395 eloop_cancel_timeout(ap_list_timer, iface, NULL); 00396 hostapd_free_aps(iface); 00397 }