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
00049
00050
00051
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
00071
00072
00073
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
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
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
00352
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
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
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
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