3 * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
4 * Copyright (c) 2003-2004, Instant802 Networks, Inc.
5 * Copyright (c) 2006, Devicescape Software, Inc.
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.
11 * Alternatively, this software may be distributed under the terms of BSD
14 * See README and COPYING for more details.
17 #include "utils/includes.h"
19 #include "utils/common.h"
20 #include "utils/eloop.h"
21 #include "common/ieee802_11_defs.h"
22 #include "common/ieee802_11_common.h"
23 #include "drivers/driver.h"
25 #include "ap_config.h"
26 #include "ieee802_11.h"
32 /* AP list is a double linked list with head->prev pointing to the end of the
33 * list and tail->next = NULL. Entries are moved to the head of the list
34 * whenever a beacon has been received from the AP in question. The tail entry
35 * in this link will thus be the least recently used entry. */
38 static int ap_list_beacon_olbc(struct hostapd_iface
*iface
, struct ap_info
*ap
)
42 if (iface
->current_mode
->mode
!= HOSTAPD_MODE_IEEE80211G
||
43 iface
->conf
->channel
!= ap
->channel
)
46 if (ap
->erp
!= -1 && (ap
->erp
& ERP_INFO_NON_ERP_PRESENT
))
49 for (i
= 0; i
< WLAN_SUPP_RATES_MAX
; i
++) {
50 int rate
= (ap
->supported_rates
[i
] & 0x7f) * 5;
51 if (rate
== 60 || rate
== 90 || rate
> 110)
59 struct ap_info
* ap_get_ap(struct hostapd_iface
*iface
, const u8
*ap
)
63 s
= iface
->ap_hash
[STA_HASH(ap
)];
64 while (s
!= NULL
&& os_memcmp(s
->addr
, ap
, ETH_ALEN
) != 0)
70 static void ap_ap_list_add(struct hostapd_iface
*iface
, struct ap_info
*ap
)
73 ap
->prev
= iface
->ap_list
->prev
;
74 iface
->ap_list
->prev
= ap
;
77 ap
->next
= iface
->ap_list
;
82 static void ap_ap_list_del(struct hostapd_iface
*iface
, struct ap_info
*ap
)
84 if (iface
->ap_list
== ap
)
85 iface
->ap_list
= ap
->next
;
87 ap
->prev
->next
= ap
->next
;
90 ap
->next
->prev
= ap
->prev
;
91 else if (iface
->ap_list
)
92 iface
->ap_list
->prev
= ap
->prev
;
96 static void ap_ap_iter_list_add(struct hostapd_iface
*iface
,
99 if (iface
->ap_iter_list
) {
100 ap
->iter_prev
= iface
->ap_iter_list
->iter_prev
;
101 iface
->ap_iter_list
->iter_prev
= ap
;
104 ap
->iter_next
= iface
->ap_iter_list
;
105 iface
->ap_iter_list
= ap
;
109 static void ap_ap_iter_list_del(struct hostapd_iface
*iface
,
112 if (iface
->ap_iter_list
== ap
)
113 iface
->ap_iter_list
= ap
->iter_next
;
115 ap
->iter_prev
->iter_next
= ap
->iter_next
;
118 ap
->iter_next
->iter_prev
= ap
->iter_prev
;
119 else if (iface
->ap_iter_list
)
120 iface
->ap_iter_list
->iter_prev
= ap
->iter_prev
;
124 static void ap_ap_hash_add(struct hostapd_iface
*iface
, struct ap_info
*ap
)
126 ap
->hnext
= iface
->ap_hash
[STA_HASH(ap
->addr
)];
127 iface
->ap_hash
[STA_HASH(ap
->addr
)] = ap
;
131 static void ap_ap_hash_del(struct hostapd_iface
*iface
, struct ap_info
*ap
)
135 s
= iface
->ap_hash
[STA_HASH(ap
->addr
)];
136 if (s
== NULL
) return;
137 if (os_memcmp(s
->addr
, ap
->addr
, ETH_ALEN
) == 0) {
138 iface
->ap_hash
[STA_HASH(ap
->addr
)] = s
->hnext
;
142 while (s
->hnext
!= NULL
&&
143 os_memcmp(s
->hnext
->addr
, ap
->addr
, ETH_ALEN
) != 0)
145 if (s
->hnext
!= NULL
)
146 s
->hnext
= s
->hnext
->hnext
;
148 printf("AP: could not remove AP " MACSTR
" from hash table\n",
153 static void ap_free_ap(struct hostapd_iface
*iface
, struct ap_info
*ap
)
155 ap_ap_hash_del(iface
, ap
);
156 ap_ap_list_del(iface
, ap
);
157 ap_ap_iter_list_del(iface
, ap
);
164 static void hostapd_free_aps(struct hostapd_iface
*iface
)
166 struct ap_info
*ap
, *prev
;
173 ap_free_ap(iface
, prev
);
176 iface
->ap_list
= NULL
;
180 int ap_ap_for_each(struct hostapd_iface
*iface
,
181 int (*func
)(struct ap_info
*s
, void *data
), void *data
)
199 static struct ap_info
* ap_ap_add(struct hostapd_iface
*iface
, const u8
*addr
)
203 ap
= os_zalloc(sizeof(struct ap_info
));
207 /* initialize AP info data */
208 os_memcpy(ap
->addr
, addr
, ETH_ALEN
);
209 ap_ap_list_add(iface
, ap
);
211 ap_ap_hash_add(iface
, ap
);
212 ap_ap_iter_list_add(iface
, ap
);
214 if (iface
->num_ap
> iface
->conf
->ap_table_max_size
&& ap
!= ap
->prev
) {
215 wpa_printf(MSG_DEBUG
, "Removing the least recently used AP "
216 MACSTR
" from AP table", MAC2STR(ap
->prev
->addr
));
217 ap_free_ap(iface
, ap
->prev
);
224 void ap_list_process_beacon(struct hostapd_iface
*iface
,
225 const struct ieee80211_mgmt
*mgmt
,
226 struct ieee802_11_elems
*elems
,
227 struct hostapd_frame_info
*fi
)
234 if (iface
->conf
->ap_table_max_size
< 1)
237 ap
= ap_get_ap(iface
, mgmt
->bssid
);
239 ap
= ap_ap_add(iface
, mgmt
->bssid
);
241 printf("Failed to allocate AP information entry\n");
247 ap
->beacon_int
= le_to_host16(mgmt
->u
.beacon
.beacon_int
);
248 ap
->capability
= le_to_host16(mgmt
->u
.beacon
.capab_info
);
251 len
= elems
->ssid_len
;
252 if (len
>= sizeof(ap
->ssid
))
253 len
= sizeof(ap
->ssid
) - 1;
254 os_memcpy(ap
->ssid
, elems
->ssid
, len
);
255 ap
->ssid
[len
] = '\0';
259 os_memset(ap
->supported_rates
, 0, WLAN_SUPP_RATES_MAX
);
261 if (elems
->supp_rates
) {
262 len
= elems
->supp_rates_len
;
263 if (len
> WLAN_SUPP_RATES_MAX
)
264 len
= WLAN_SUPP_RATES_MAX
;
265 os_memcpy(ap
->supported_rates
, elems
->supp_rates
, len
);
267 if (elems
->ext_supp_rates
) {
269 if (len
+ elems
->ext_supp_rates_len
> WLAN_SUPP_RATES_MAX
)
270 len2
= WLAN_SUPP_RATES_MAX
- len
;
272 len2
= elems
->ext_supp_rates_len
;
273 os_memcpy(ap
->supported_rates
+ len
, elems
->ext_supp_rates
,
277 ap
->wpa
= elems
->wpa_ie
!= NULL
;
279 if (elems
->erp_info
&& elems
->erp_info_len
== 1)
280 ap
->erp
= elems
->erp_info
[0];
284 if (elems
->ds_params
&& elems
->ds_params_len
== 1)
285 ap
->channel
= elems
->ds_params
[0];
287 ap
->channel
= fi
->channel
;
289 if (elems
->ht_capabilities
)
295 time(&ap
->last_beacon
);
297 ap
->ssi_signal
= fi
->ssi_signal
;
298 ap
->datarate
= fi
->datarate
;
301 if (!new_ap
&& ap
!= iface
->ap_list
) {
302 /* move AP entry into the beginning of the list so that the
303 * oldest entry is always in the end of the list */
304 ap_ap_list_del(iface
, ap
);
305 ap_ap_list_add(iface
, ap
);
309 ap_list_beacon_olbc(iface
, ap
)) {
311 wpa_printf(MSG_DEBUG
, "OLBC AP detected: " MACSTR
" - enable "
312 "protection", MAC2STR(ap
->addr
));
316 #ifdef CONFIG_IEEE80211N
317 if (!iface
->olbc_ht
&& !ap
->ht_support
) {
319 hostapd_ht_operation_update(iface
);
320 wpa_printf(MSG_DEBUG
, "OLBC HT AP detected: " MACSTR
321 " - enable protection", MAC2STR(ap
->addr
));
324 #endif /* CONFIG_IEEE80211N */
327 ieee802_11_set_beacons(iface
);
331 static void ap_list_timer(void *eloop_ctx
, void *timeout_ctx
)
333 struct hostapd_iface
*iface
= eloop_ctx
;
338 eloop_register_timeout(10, 0, ap_list_timer
, iface
, NULL
);
345 while (iface
->ap_list
) {
346 ap
= iface
->ap_list
->prev
;
347 if (ap
->last_beacon
+ iface
->conf
->ap_table_expiration_time
>=
351 ap_free_ap(iface
, ap
);
354 if (iface
->olbc
|| iface
->olbc_ht
) {
359 while (ap
&& (olbc
== 0 || olbc_ht
== 0)) {
360 if (ap_list_beacon_olbc(iface
, ap
))
366 if (!olbc
&& iface
->olbc
) {
367 wpa_printf(MSG_DEBUG
, "OLBC not detected anymore");
371 #ifdef CONFIG_IEEE80211N
372 if (!olbc_ht
&& iface
->olbc_ht
) {
373 wpa_printf(MSG_DEBUG
, "OLBC HT not detected anymore");
375 hostapd_ht_operation_update(iface
);
378 #endif /* CONFIG_IEEE80211N */
382 ieee802_11_set_beacons(iface
);
386 int ap_list_init(struct hostapd_iface
*iface
)
388 eloop_register_timeout(10, 0, ap_list_timer
, iface
, NULL
);
393 void ap_list_deinit(struct hostapd_iface
*iface
)
395 eloop_cancel_timeout(ap_list_timer
, iface
, NULL
);
396 hostapd_free_aps(iface
);