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