18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* 28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hostapd / AP table 38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> 48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2003-2004, Instant802 Networks, Inc. 58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2006, Devicescape Software, Inc. 68d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This program is free software; you can redistribute it and/or modify 88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * it under the terms of the GNU General Public License version 2 as 98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * published by the Free Software Foundation. 108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD 128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * license. 138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * 148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * See README and COPYING for more details. 158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */ 168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/includes.h" 188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/common.h" 208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/eloop.h" 218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_defs.h" 228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_common.h" 238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "drivers/driver.h" 248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "hostapd.h" 258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap_config.h" 268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ieee802_11.h" 278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "sta_info.h" 288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "beacon.h" 298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap_list.h" 308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* AP list is a double linked list with head->prev pointing to the end of the 338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * list and tail->next = NULL. Entries are moved to the head of the list 348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * whenever a beacon has been received from the AP in question. The tail entry 358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * in this link will thus be the least recently used entry. */ 368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap) 398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int i; 418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G || 438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->conf->channel != ap->channel) 448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ap->erp != -1 && (ap->erp & ERP_INFO_NON_ERP_PRESENT)) 478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) { 508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int rate = (ap->supported_rates[i] & 0x7f) * 5; 518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (rate == 60 || rate == 90 || rate > 110) 528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 1; 568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap) 608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ap_info *s; 628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt s = iface->ap_hash[STA_HASH(ap)]; 648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0) 658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt s = s->hnext; 668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return s; 678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ap_ap_list_add(struct hostapd_iface *iface, struct ap_info *ap) 718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->ap_list) { 738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->prev = iface->ap_list->prev; 748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->ap_list->prev = ap; 758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->prev = ap; 778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->next = iface->ap_list; 788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->ap_list = ap; 798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap) 838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->ap_list == ap) 858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->ap_list = ap->next; 868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->prev->next = ap->next; 888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ap->next) 908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->next->prev = ap->prev; 918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (iface->ap_list) 928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->ap_list->prev = ap->prev; 938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ap_ap_iter_list_add(struct hostapd_iface *iface, 978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ap_info *ap) 988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->ap_iter_list) { 1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->iter_prev = iface->ap_iter_list->iter_prev; 1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->ap_iter_list->iter_prev = ap; 1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } else 1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->iter_prev = ap; 1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->iter_next = iface->ap_iter_list; 1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->ap_iter_list = ap; 1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ap_ap_iter_list_del(struct hostapd_iface *iface, 1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ap_info *ap) 1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->ap_iter_list == ap) 1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->ap_iter_list = ap->iter_next; 1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->iter_prev->iter_next = ap->iter_next; 1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ap->iter_next) 1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->iter_next->iter_prev = ap->iter_prev; 1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (iface->ap_iter_list) 1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->ap_iter_list->iter_prev = ap->iter_prev; 1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap) 1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->hnext = iface->ap_hash[STA_HASH(ap->addr)]; 1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->ap_hash[STA_HASH(ap->addr)] = ap; 1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap) 1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ap_info *s; 1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt s = iface->ap_hash[STA_HASH(ap->addr)]; 1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (s == NULL) return; 1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) { 1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->ap_hash[STA_HASH(ap->addr)] = s->hnext; 1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (s->hnext != NULL && 1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0) 1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt s = s->hnext; 1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (s->hnext != NULL) 1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt s->hnext = s->hnext->hnext; 1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("AP: could not remove AP " MACSTR " from hash table\n", 1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MAC2STR(ap->addr)); 1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap) 1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap_ap_hash_del(iface, ap); 1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap_ap_list_del(iface, ap); 1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap_ap_iter_list_del(iface, ap); 1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->num_ap--; 1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_free(ap); 1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void hostapd_free_aps(struct hostapd_iface *iface) 1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ap_info *ap, *prev; 1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap = iface->ap_list; 1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (ap) { 1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt prev = ap; 1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap = ap->next; 1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap_free_ap(iface, prev); 1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->ap_list = NULL; 1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ap_ap_for_each(struct hostapd_iface *iface, 1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int (*func)(struct ap_info *s, void *data), void *data) 1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ap_info *s; 1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int ret = 0; 1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt s = iface->ap_list; 1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (s) { 1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ret = func(s, data); 1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ret) 1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt s = s->next; 1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ret; 1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr) 2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ap_info *ap; 2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap = os_zalloc(sizeof(struct ap_info)); 2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ap == NULL) 2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return NULL; 2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* initialize AP info data */ 2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(ap->addr, addr, ETH_ALEN); 2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap_ap_list_add(iface, ap); 2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->num_ap++; 2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap_ap_hash_add(iface, ap); 2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap_ap_iter_list_add(iface, ap); 2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) { 2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "Removing the least recently used AP " 2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt MACSTR " from AP table", MAC2STR(ap->prev->addr)); 2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap_free_ap(iface, ap->prev); 2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return ap; 2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ap_list_process_beacon(struct hostapd_iface *iface, 2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt const struct ieee80211_mgmt *mgmt, 2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ieee802_11_elems *elems, 2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_frame_info *fi) 2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ap_info *ap; 2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct os_time now; 2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int new_ap = 0; 2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt size_t len; 2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int set_beacon = 0; 2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->conf->ap_table_max_size < 1) 2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap = ap_get_ap(iface, mgmt->bssid); 2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ap) { 2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap = ap_ap_add(iface, mgmt->bssid); 2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ap) { 2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt printf("Failed to allocate AP information entry\n"); 2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt new_ap = 1; 2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int); 2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->capability = le_to_host16(mgmt->u.beacon.capab_info); 2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (elems->ssid) { 2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = elems->ssid_len; 2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len >= sizeof(ap->ssid)) 2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = sizeof(ap->ssid) - 1; 2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(ap->ssid, elems->ssid, len); 2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->ssid[len] = '\0'; 2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->ssid_len = len; 2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memset(ap->supported_rates, 0, WLAN_SUPP_RATES_MAX); 2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = 0; 2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (elems->supp_rates) { 2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = elems->supp_rates_len; 2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len > WLAN_SUPP_RATES_MAX) 2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len = WLAN_SUPP_RATES_MAX; 2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(ap->supported_rates, elems->supp_rates, len); 2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (elems->ext_supp_rates) { 2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int len2; 2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (len + elems->ext_supp_rates_len > WLAN_SUPP_RATES_MAX) 2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len2 = WLAN_SUPP_RATES_MAX - len; 2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len2 = elems->ext_supp_rates_len; 2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_memcpy(ap->supported_rates + len, elems->ext_supp_rates, 2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt len2); 2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->wpa = elems->wpa_ie != NULL; 2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (elems->erp_info && elems->erp_info_len == 1) 2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->erp = elems->erp_info[0]; 2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->erp = -1; 2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (elems->ds_params && elems->ds_params_len == 1) 2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->channel = elems->ds_params[0]; 2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else if (fi) 2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->channel = fi->channel; 2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (elems->ht_capabilities) 2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->ht_support = 1; 2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt else 2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->ht_support = 0; 2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->num_beacons++; 2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_get_time(&now); 2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->last_beacon = now.sec; 2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (fi) { 2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->ssi_signal = fi->ssi_signal; 3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap->datarate = fi->datarate; 3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!new_ap && ap != iface->ap_list) { 3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt /* move AP entry into the beginning of the list so that the 3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * oldest entry is always in the end of the list */ 3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap_ap_list_del(iface, ap); 3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap_ap_list_add(iface, ap); 3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->olbc && 3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap_list_beacon_olbc(iface, ap)) { 3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->olbc = 1; 3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR " - enable " 3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt "protection", MAC2STR(ap->addr)); 3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt set_beacon++; 3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211N 3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->olbc_ht && !ap->ht_support) { 3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->olbc_ht = 1; 3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_ht_operation_update(iface); 3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR 3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt " - enable protection", MAC2STR(ap->addr)); 3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt set_beacon++; 3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211N */ 3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (set_beacon) 3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee802_11_set_beacons(iface); 3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ap_list_timer(void *eloop_ctx, void *timeout_ctx) 3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct hostapd_iface *iface = eloop_ctx; 3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct os_time now; 3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt struct ap_info *ap; 3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int set_beacon = 0; 3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_register_timeout(10, 0, ap_list_timer, iface, NULL); 3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!iface->ap_list) 3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return; 3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt os_get_time(&now); 3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (iface->ap_list) { 3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap = iface->ap_list->prev; 3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ap->last_beacon + iface->conf->ap_table_expiration_time >= 3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt now.sec) 3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt break; 3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap_free_ap(iface, ap); 3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (iface->olbc || iface->olbc_ht) { 3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int olbc = 0; 3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt int olbc_ht = 0; 3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap = iface->ap_list; 3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt while (ap && (olbc == 0 || olbc_ht == 0)) { 3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (ap_list_beacon_olbc(iface, ap)) 3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt olbc = 1; 3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!ap->ht_support) 3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt olbc_ht = 1; 3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ap = ap->next; 3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!olbc && iface->olbc) { 3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "OLBC not detected anymore"); 3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->olbc = 0; 3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt set_beacon++; 3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211N 3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (!olbc_ht && iface->olbc_ht) { 3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore"); 3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt iface->olbc_ht = 0; 3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_ht_operation_update(iface); 3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt set_beacon++; 3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211N */ 3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt } 3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt if (set_beacon) 3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt ieee802_11_set_beacons(iface); 3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ap_list_init(struct hostapd_iface *iface) 3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_register_timeout(10, 0, ap_list_timer, iface, NULL); 3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt return 0; 3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt 3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ap_list_deinit(struct hostapd_iface *iface) 3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{ 3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt eloop_cancel_timeout(ap_list_timer, iface, NULL); 3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt hostapd_free_aps(iface); 3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt} 400