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