]> git.ipfire.org Git - thirdparty/hostap.git/blame - src/ap/ap_list.c
Move generic AP functionality implementation into src/ap
[thirdparty/hostap.git] / src / ap / ap_list.c
CommitLineData
6fc6879b
JM
1/*
2 * hostapd / AP table
1057d78e 3 * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
71b6ae14
TW
4 * Copyright (c) 2003-2004, Instant802 Networks, Inc.
5 * Copyright (c) 2006, Devicescape Software, Inc.
6fc6879b
JM
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * Alternatively, this software may be distributed under the terms of BSD
12 * license.
13 *
14 * See README and COPYING for more details.
15 */
16
1057d78e 17#include "utils/includes.h"
6fc6879b 18
1057d78e
JM
19#include "utils/common.h"
20#include "utils/eloop.h"
21#include "drivers/driver.h"
6fc6879b 22#include "hostapd.h"
b1c0e297 23#include "config.h"
6fc6879b 24#include "ieee802_11.h"
97234b50 25#include "sta_info.h"
6fc6879b 26#include "beacon.h"
1057d78e 27#include "ap_list.h"
6fc6879b
JM
28
29
6fc6879b
JM
30/* AP list is a double linked list with head->prev pointing to the end of the
31 * list and tail->next = NULL. Entries are moved to the head of the list
32 * whenever a beacon has been received from the AP in question. The tail entry
33 * in this link will thus be the least recently used entry. */
34
35
6fc6879b
JM
36static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
37{
38 int i;
39
40 if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
6fc6879b
JM
41 iface->conf->channel != ap->channel)
42 return 0;
43
44 if (ap->erp != -1 && (ap->erp & ERP_INFO_NON_ERP_PRESENT))
45 return 1;
46
47 for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
48 int rate = (ap->supported_rates[i] & 0x7f) * 5;
49 if (rate == 60 || rate == 90 || rate > 110)
50 return 0;
51 }
52
53 return 1;
54}
55
56
b57e086c 57struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *ap)
6fc6879b
JM
58{
59 struct ap_info *s;
60
61 s = iface->ap_hash[STA_HASH(ap)];
62 while (s != NULL && os_memcmp(s->addr, ap, ETH_ALEN) != 0)
63 s = s->hnext;
64 return s;
65}
66
67
68static void ap_ap_list_add(struct hostapd_iface *iface, struct ap_info *ap)
69{
70 if (iface->ap_list) {
71 ap->prev = iface->ap_list->prev;
72 iface->ap_list->prev = ap;
73 } else
74 ap->prev = ap;
75 ap->next = iface->ap_list;
76 iface->ap_list = ap;
77}
78
79
80static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap)
81{
82 if (iface->ap_list == ap)
83 iface->ap_list = ap->next;
84 else
85 ap->prev->next = ap->next;
86
87 if (ap->next)
88 ap->next->prev = ap->prev;
89 else if (iface->ap_list)
90 iface->ap_list->prev = ap->prev;
91}
92
93
94static void ap_ap_iter_list_add(struct hostapd_iface *iface,
95 struct ap_info *ap)
96{
97 if (iface->ap_iter_list) {
98 ap->iter_prev = iface->ap_iter_list->iter_prev;
99 iface->ap_iter_list->iter_prev = ap;
100 } else
101 ap->iter_prev = ap;
102 ap->iter_next = iface->ap_iter_list;
103 iface->ap_iter_list = ap;
104}
105
106
107static void ap_ap_iter_list_del(struct hostapd_iface *iface,
108 struct ap_info *ap)
109{
110 if (iface->ap_iter_list == ap)
111 iface->ap_iter_list = ap->iter_next;
112 else
113 ap->iter_prev->iter_next = ap->iter_next;
114
115 if (ap->iter_next)
116 ap->iter_next->iter_prev = ap->iter_prev;
117 else if (iface->ap_iter_list)
118 iface->ap_iter_list->iter_prev = ap->iter_prev;
119}
120
121
122static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
123{
124 ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
125 iface->ap_hash[STA_HASH(ap->addr)] = ap;
126}
127
128
129static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap)
130{
131 struct ap_info *s;
132
133 s = iface->ap_hash[STA_HASH(ap->addr)];
134 if (s == NULL) return;
135 if (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) {
136 iface->ap_hash[STA_HASH(ap->addr)] = s->hnext;
137 return;
138 }
139
140 while (s->hnext != NULL &&
141 os_memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0)
142 s = s->hnext;
143 if (s->hnext != NULL)
144 s->hnext = s->hnext->hnext;
145 else
146 printf("AP: could not remove AP " MACSTR " from hash table\n",
147 MAC2STR(ap->addr));
148}
149
150
151static void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap)
152{
153 ap_ap_hash_del(iface, ap);
154 ap_ap_list_del(iface, ap);
155 ap_ap_iter_list_del(iface, ap);
156
157 iface->num_ap--;
158 os_free(ap);
159}
160
161
162static void hostapd_free_aps(struct hostapd_iface *iface)
163{
164 struct ap_info *ap, *prev;
165
166 ap = iface->ap_list;
167
168 while (ap) {
169 prev = ap;
170 ap = ap->next;
171 ap_free_ap(iface, prev);
172 }
173
174 iface->ap_list = NULL;
175}
176
177
178int ap_ap_for_each(struct hostapd_iface *iface,
179 int (*func)(struct ap_info *s, void *data), void *data)
180{
181 struct ap_info *s;
182 int ret = 0;
183
184 s = iface->ap_list;
185
186 while (s) {
187 ret = func(s, data);
188 if (ret)
189 break;
190 s = s->next;
191 }
192
193 return ret;
194}
195
196
b57e086c 197static struct ap_info * ap_ap_add(struct hostapd_iface *iface, const u8 *addr)
6fc6879b
JM
198{
199 struct ap_info *ap;
200
201 ap = os_zalloc(sizeof(struct ap_info));
202 if (ap == NULL)
203 return NULL;
204
205 /* initialize AP info data */
206 os_memcpy(ap->addr, addr, ETH_ALEN);
207 ap_ap_list_add(iface, ap);
208 iface->num_ap++;
209 ap_ap_hash_add(iface, ap);
210 ap_ap_iter_list_add(iface, ap);
211
212 if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) {
213 wpa_printf(MSG_DEBUG, "Removing the least recently used AP "
214 MACSTR " from AP table", MAC2STR(ap->prev->addr));
6fc6879b
JM
215 ap_free_ap(iface, ap->prev);
216 }
217
218 return ap;
219}
220
221
222void ap_list_process_beacon(struct hostapd_iface *iface,
b57e086c 223 const struct ieee80211_mgmt *mgmt,
6fc6879b
JM
224 struct ieee802_11_elems *elems,
225 struct hostapd_frame_info *fi)
226{
227 struct ap_info *ap;
228 int new_ap = 0;
229 size_t len;
de9289c8 230 int set_beacon = 0;
6fc6879b
JM
231
232 if (iface->conf->ap_table_max_size < 1)
233 return;
234
235 ap = ap_get_ap(iface, mgmt->bssid);
236 if (!ap) {
237 ap = ap_ap_add(iface, mgmt->bssid);
238 if (!ap) {
239 printf("Failed to allocate AP information entry\n");
240 return;
241 }
242 new_ap = 1;
243 }
244
245 ap->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int);
246 ap->capability = le_to_host16(mgmt->u.beacon.capab_info);
247
248 if (elems->ssid) {
249 len = elems->ssid_len;
250 if (len >= sizeof(ap->ssid))
251 len = sizeof(ap->ssid) - 1;
252 os_memcpy(ap->ssid, elems->ssid, len);
253 ap->ssid[len] = '\0';
254 ap->ssid_len = len;
255 }
256
257 os_memset(ap->supported_rates, 0, WLAN_SUPP_RATES_MAX);
258 len = 0;
259 if (elems->supp_rates) {
260 len = elems->supp_rates_len;
261 if (len > WLAN_SUPP_RATES_MAX)
262 len = WLAN_SUPP_RATES_MAX;
263 os_memcpy(ap->supported_rates, elems->supp_rates, len);
264 }
265 if (elems->ext_supp_rates) {
266 int len2;
267 if (len + elems->ext_supp_rates_len > WLAN_SUPP_RATES_MAX)
268 len2 = WLAN_SUPP_RATES_MAX - len;
269 else
270 len2 = elems->ext_supp_rates_len;
271 os_memcpy(ap->supported_rates + len, elems->ext_supp_rates,
272 len2);
273 }
274
275 ap->wpa = elems->wpa_ie != NULL;
276
277 if (elems->erp_info && elems->erp_info_len == 1)
278 ap->erp = elems->erp_info[0];
279 else
280 ap->erp = -1;
281
282 if (elems->ds_params && elems->ds_params_len == 1)
283 ap->channel = elems->ds_params[0];
284 else if (fi)
285 ap->channel = fi->channel;
286
de9289c8
JM
287 if (elems->ht_capabilities)
288 ap->ht_support = 1;
289 else
290 ap->ht_support = 0;
291
6fc6879b
JM
292 ap->num_beacons++;
293 time(&ap->last_beacon);
294 if (fi) {
6fc6879b
JM
295 ap->ssi_signal = fi->ssi_signal;
296 ap->datarate = fi->datarate;
297 }
298
61693eaa 299 if (!new_ap && ap != iface->ap_list) {
6fc6879b
JM
300 /* move AP entry into the beginning of the list so that the
301 * oldest entry is always in the end of the list */
302 ap_ap_list_del(iface, ap);
303 ap_ap_list_add(iface, ap);
304 }
305
306 if (!iface->olbc &&
307 ap_list_beacon_olbc(iface, ap)) {
6fc6879b
JM
308 iface->olbc = 1;
309 wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR " - enable "
310 "protection", MAC2STR(ap->addr));
de9289c8 311 set_beacon++;
6fc6879b 312 }
de9289c8
JM
313
314#ifdef CONFIG_IEEE80211N
eb53b752 315 if (!iface->olbc_ht && !ap->ht_support) {
de9289c8
JM
316 iface->olbc_ht = 1;
317 hostapd_ht_operation_update(iface);
318 wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR
319 " - enable protection", MAC2STR(ap->addr));
320 set_beacon++;
321 }
322#endif /* CONFIG_IEEE80211N */
323
324 if (set_beacon)
325 ieee802_11_set_beacons(iface);
6fc6879b
JM
326}
327
328
329static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
330{
331 struct hostapd_iface *iface = eloop_ctx;
332 time_t now;
333 struct ap_info *ap;
de9289c8 334 int set_beacon = 0;
6fc6879b
JM
335
336 eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
337
338 if (!iface->ap_list)
339 return;
340
341 time(&now);
342
6fc6879b
JM
343 while (iface->ap_list) {
344 ap = iface->ap_list->prev;
345 if (ap->last_beacon + iface->conf->ap_table_expiration_time >=
346 now)
347 break;
348
6fc6879b
JM
349 ap_free_ap(iface, ap);
350 }
351
de9289c8 352 if (iface->olbc || iface->olbc_ht) {
6fc6879b 353 int olbc = 0;
de9289c8
JM
354 int olbc_ht = 0;
355
6fc6879b 356 ap = iface->ap_list;
de9289c8
JM
357 while (ap && (olbc == 0 || olbc_ht == 0)) {
358 if (ap_list_beacon_olbc(iface, ap))
6fc6879b 359 olbc = 1;
eb53b752 360 if (!ap->ht_support)
de9289c8 361 olbc_ht = 1;
6fc6879b
JM
362 ap = ap->next;
363 }
de9289c8 364 if (!olbc && iface->olbc) {
6fc6879b
JM
365 wpa_printf(MSG_DEBUG, "OLBC not detected anymore");
366 iface->olbc = 0;
de9289c8
JM
367 set_beacon++;
368 }
369#ifdef CONFIG_IEEE80211N
370 if (!olbc_ht && iface->olbc_ht) {
371 wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore");
372 iface->olbc_ht = 0;
373 hostapd_ht_operation_update(iface);
374 set_beacon++;
6fc6879b 375 }
de9289c8 376#endif /* CONFIG_IEEE80211N */
6fc6879b 377 }
de9289c8
JM
378
379 if (set_beacon)
380 ieee802_11_set_beacons(iface);
6fc6879b
JM
381}
382
383
384int ap_list_init(struct hostapd_iface *iface)
385{
386 eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
387 return 0;
388}
389
390
391void ap_list_deinit(struct hostapd_iface *iface)
392{
393 eloop_cancel_timeout(ap_list_timer, iface, NULL);
394 hostapd_free_aps(iface);
395}