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 *
7c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
8c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/includes.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/common.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/eloop.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_defs.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/ieee802_11_common.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "hostapd.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap_config.h"
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ieee802_11.h"
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "sta_info.h"
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "beacon.h"
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap_list.h"
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* AP list is a double linked list with head->prev pointing to the end of the
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * list and tail->next = NULL. Entries are moved to the head of the list
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * whenever a beacon has been received from the AP in question. The tail entry
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * in this link will thus be the least recently used entry. */
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
35ed003d2a93648e6201272d2fb8212cbc01085928Dmitry Shmidt	if (iface->current_mode == NULL ||
36ed003d2a93648e6201272d2fb8212cbc01085928Dmitry Shmidt	    iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    iface->conf->channel != ap->channel)
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->erp != -1 && (ap->erp & ERP_INFO_NON_ERP_PRESENT))
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 1;
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int rate = (ap->supported_rates[i] & 0x7f) * 5;
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (rate == 60 || rate == 90 || rate > 110)
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return 0;
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 1;
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
53444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidtstatic struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ap_info *s;
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	s = iface->ap_hash[STA_HASH(ap)];
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0)
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		s = s->hnext;
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return s;
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ap_ap_list_add(struct hostapd_iface *iface, struct ap_info *ap)
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (iface->ap_list) {
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap->prev = iface->ap_list->prev;
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iface->ap_list->prev = ap;
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap->prev = ap;
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->next = iface->ap_list;
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iface->ap_list = ap;
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap)
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (iface->ap_list == ap)
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iface->ap_list = ap->next;
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap->prev->next = ap->next;
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap->next)
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap->next->prev = ap->prev;
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (iface->ap_list)
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iface->ap_list->prev = ap->prev;
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iface->ap_hash[STA_HASH(ap->addr)] = ap;
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap)
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ap_info *s;
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	s = iface->ap_hash[STA_HASH(ap->addr)];
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (s == NULL) return;
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) {
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iface->ap_hash[STA_HASH(ap->addr)] = s->hnext;
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (s->hnext != NULL &&
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	       os_memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0)
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		s = s->hnext;
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (s->hnext != NULL)
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		s->hnext = s->hnext->hnext;
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		printf("AP: could not remove AP " MACSTR " from hash table\n",
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		       MAC2STR(ap->addr));
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap)
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap_ap_hash_del(iface, ap);
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap_ap_list_del(iface, ap);
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iface->num_ap--;
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(ap);
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void hostapd_free_aps(struct hostapd_iface *iface)
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ap_info *ap, *prev;
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap = iface->ap_list;
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (ap) {
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = ap;
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap = ap->next;
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap_free_ap(iface, prev);
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iface->ap_list = NULL;
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr)
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ap_info *ap;
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap = os_zalloc(sizeof(struct ap_info));
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (ap == NULL)
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* initialize AP info data */
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(ap->addr, addr, ETH_ALEN);
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap_ap_list_add(iface, ap);
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	iface->num_ap++;
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap_ap_hash_add(iface, ap);
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) {
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Removing the least recently used AP "
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   MACSTR " from AP table", MAC2STR(ap->prev->addr));
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap_free_ap(iface, ap->prev);
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return ap;
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ap_list_process_beacon(struct hostapd_iface *iface,
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    const struct ieee80211_mgmt *mgmt,
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    struct ieee802_11_elems *elems,
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    struct hostapd_frame_info *fi)
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ap_info *ap;
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int new_ap = 0;
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int set_beacon = 0;
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (iface->conf->ap_table_max_size < 1)
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ap = ap_get_ap(iface, mgmt->bssid);
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!ap) {
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap = ap_ap_add(iface, mgmt->bssid);
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!ap) {
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			printf("Failed to allocate AP information entry\n");
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return;
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		new_ap = 1;
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	merge_byte_arrays(ap->supported_rates, WLAN_SUPP_RATES_MAX,
19261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			  elems->supp_rates, elems->supp_rates_len,
19361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			  elems->ext_supp_rates, elems->ext_supp_rates_len);
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (elems->erp_info && elems->erp_info_len == 1)
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap->erp = elems->erp_info[0];
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap->erp = -1;
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (elems->ds_params && elems->ds_params_len == 1)
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap->channel = elems->ds_params[0];
202444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	else if (elems->ht_operation && elems->ht_operation_len >= 1)
203444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		ap->channel = elems->ht_operation[0];
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (fi)
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap->channel = fi->channel;
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (elems->ht_capabilities)
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap->ht_support = 1;
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap->ht_support = 0;
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	os_get_reltime(&ap->last_beacon);
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!new_ap && ap != iface->ap_list) {
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* move AP entry into the beginning of the list so that the
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * oldest entry is always in the end of the list */
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap_ap_list_del(iface, ap);
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap_ap_list_add(iface, ap);
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!iface->olbc &&
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    ap_list_beacon_olbc(iface, ap)) {
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iface->olbc = 1;
224444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt		wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR
225444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt			   " (channel %d) - enable protection",
226444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt			   MAC2STR(ap->addr), ap->channel);
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		set_beacon++;
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211N
231444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	if (!iface->olbc_ht && !ap->ht_support &&
232444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	    (ap->channel == 0 ||
233444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	     ap->channel == iface->conf->channel ||
234444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	     ap->channel == iface->conf->channel +
235444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt	     iface->conf->secondary_channel * 4)) {
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		iface->olbc_ht = 1;
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hostapd_ht_operation_update(iface);
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR
239444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt			   " (channel %d) - enable protection",
240444d567b27731d8572ef37697dd12fd1c37c2f24Dmitry Shmidt			   MAC2STR(ap->addr), ap->channel);
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		set_beacon++;
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211N */
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (set_beacon)
24604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		ieee802_11_update_beacons(iface);
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_iface *iface = eloop_ctx;
25304f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	struct os_reltime now;
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ap_info *ap;
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int set_beacon = 0;
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!iface->ap_list)
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
26204f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt	os_get_reltime(&now);
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (iface->ap_list) {
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap = iface->ap_list->prev;
26604f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt		if (!os_reltime_expired(&now, &ap->last_beacon,
26704f534e89ed127da4077485376f24debc50d80d5Dmitry Shmidt					iface->conf->ap_table_expiration_time))
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap_free_ap(iface, ap);
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (iface->olbc || iface->olbc_ht) {
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int olbc = 0;
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int olbc_ht = 0;
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ap = iface->ap_list;
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		while (ap && (olbc == 0 || olbc_ht == 0)) {
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (ap_list_beacon_olbc(iface, ap))
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				olbc = 1;
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (!ap->ht_support)
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				olbc_ht = 1;
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			ap = ap->next;
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!olbc && iface->olbc) {
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "OLBC not detected anymore");
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			iface->olbc = 0;
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			set_beacon++;
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IEEE80211N
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!olbc_ht && iface->olbc_ht) {
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore");
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			iface->olbc_ht = 0;
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			hostapd_ht_operation_update(iface);
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			set_beacon++;
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IEEE80211N */
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (set_beacon)
30104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		ieee802_11_update_beacons(iface);
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint ap_list_init(struct hostapd_iface *iface)
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid ap_list_deinit(struct hostapd_iface *iface)
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(ap_list_timer, iface, NULL);
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hostapd_free_aps(iface);
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
317