3 * Copyright 2002-2003, Jouni Malinen <j@w1.fi>
4 * Copyright 2003-2004, Instant802 Networks, Inc.
5 * Copyright 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.
20 #include "ieee802_11.h"
23 #include "hw_features.h"
27 struct ieee80211_frame_info
{
43 /* Note: this structure is otherwise identical to capture format used
44 * in linux-wlan-ng, but this additional field is used to provide meta
45 * data about the frame to hostapd. This was the easiest method for
46 * providing this information, but this might change in the future. */
48 } __attribute__ ((packed
));
51 enum ieee80211_phytype
{
52 ieee80211_phytype_fhss_dot11_97
= 1,
53 ieee80211_phytype_dsss_dot11_97
= 2,
54 ieee80211_phytype_irbaseband
= 3,
55 ieee80211_phytype_dsss_dot11_b
= 4,
56 ieee80211_phytype_pbcc_dot11_b
= 5,
57 ieee80211_phytype_ofdm_dot11_g
= 6,
58 ieee80211_phytype_pbcc_dot11_g
= 7,
59 ieee80211_phytype_ofdm_dot11_a
= 8,
60 ieee80211_phytype_dsss_dot11_turbog
= 255,
61 ieee80211_phytype_dsss_dot11_turbo
= 256,
65 /* AP list is a double linked list with head->prev pointing to the end of the
66 * list and tail->next = NULL. Entries are moved to the head of the list
67 * whenever a beacon has been received from the AP in question. The tail entry
68 * in this link will thus be the least recently used entry. */
71 static void ap_list_new_ap(struct hostapd_iface
*iface
, struct ap_info
*ap
)
73 wpa_printf(MSG_DEBUG
, "New AP detected: " MACSTR
, MAC2STR(ap
->addr
));
75 /* TODO: could send a notification message to an external program that
76 * would then determine whether a rogue AP has been detected */
80 static void ap_list_expired_ap(struct hostapd_iface
*iface
, struct ap_info
*ap
)
82 wpa_printf(MSG_DEBUG
, "AP info expired: " MACSTR
, MAC2STR(ap
->addr
));
84 /* TODO: could send a notification message to an external program */
88 static int ap_list_beacon_olbc(struct hostapd_iface
*iface
, struct ap_info
*ap
)
92 if (iface
->current_mode
->mode
!= HOSTAPD_MODE_IEEE80211G
||
93 ap
->phytype
!= ieee80211_phytype_pbcc_dot11_g
||
94 iface
->conf
->channel
!= ap
->channel
)
97 if (ap
->erp
!= -1 && (ap
->erp
& ERP_INFO_NON_ERP_PRESENT
))
100 for (i
= 0; i
< WLAN_SUPP_RATES_MAX
; i
++) {
101 int rate
= (ap
->supported_rates
[i
] & 0x7f) * 5;
102 if (rate
== 60 || rate
== 90 || rate
> 110)
110 struct ap_info
* ap_get_ap(struct hostapd_iface
*iface
, u8
*ap
)
114 s
= iface
->ap_hash
[STA_HASH(ap
)];
115 while (s
!= NULL
&& memcmp(s
->addr
, ap
, ETH_ALEN
) != 0)
121 static void ap_ap_list_add(struct hostapd_iface
*iface
, struct ap_info
*ap
)
123 if (iface
->ap_list
) {
124 ap
->prev
= iface
->ap_list
->prev
;
125 iface
->ap_list
->prev
= ap
;
128 ap
->next
= iface
->ap_list
;
133 static void ap_ap_list_del(struct hostapd_iface
*iface
, struct ap_info
*ap
)
135 if (iface
->ap_list
== ap
)
136 iface
->ap_list
= ap
->next
;
138 ap
->prev
->next
= ap
->next
;
141 ap
->next
->prev
= ap
->prev
;
142 else if (iface
->ap_list
)
143 iface
->ap_list
->prev
= ap
->prev
;
147 static void ap_ap_iter_list_add(struct hostapd_iface
*iface
,
150 if (iface
->ap_iter_list
) {
151 ap
->iter_prev
= iface
->ap_iter_list
->iter_prev
;
152 iface
->ap_iter_list
->iter_prev
= ap
;
155 ap
->iter_next
= iface
->ap_iter_list
;
156 iface
->ap_iter_list
= ap
;
160 static void ap_ap_iter_list_del(struct hostapd_iface
*iface
,
163 if (iface
->ap_iter_list
== ap
)
164 iface
->ap_iter_list
= ap
->iter_next
;
166 ap
->iter_prev
->iter_next
= ap
->iter_next
;
169 ap
->iter_next
->iter_prev
= ap
->iter_prev
;
170 else if (iface
->ap_iter_list
)
171 iface
->ap_iter_list
->iter_prev
= ap
->iter_prev
;
175 static void ap_ap_hash_add(struct hostapd_iface
*iface
, struct ap_info
*ap
)
177 ap
->hnext
= iface
->ap_hash
[STA_HASH(ap
->addr
)];
178 iface
->ap_hash
[STA_HASH(ap
->addr
)] = ap
;
182 static void ap_ap_hash_del(struct hostapd_iface
*iface
, struct ap_info
*ap
)
186 s
= iface
->ap_hash
[STA_HASH(ap
->addr
)];
187 if (s
== NULL
) return;
188 if (memcmp(s
->addr
, ap
->addr
, ETH_ALEN
) == 0) {
189 iface
->ap_hash
[STA_HASH(ap
->addr
)] = s
->hnext
;
193 while (s
->hnext
!= NULL
&&
194 memcmp(s
->hnext
->addr
, ap
->addr
, ETH_ALEN
) != 0)
196 if (s
->hnext
!= NULL
)
197 s
->hnext
= s
->hnext
->hnext
;
199 printf("AP: could not remove AP " MACSTR
" from hash table\n",
204 static void ap_free_ap(struct hostapd_iface
*iface
, struct ap_info
*ap
)
206 ap_ap_hash_del(iface
, ap
);
207 ap_ap_list_del(iface
, ap
);
208 ap_ap_iter_list_del(iface
, ap
);
215 static void hostapd_free_aps(struct hostapd_iface
*iface
)
217 struct ap_info
*ap
, *prev
;
224 ap_free_ap(iface
, prev
);
227 iface
->ap_list
= NULL
;
231 int ap_ap_for_each(struct hostapd_iface
*iface
,
232 int (*func
)(struct ap_info
*s
, void *data
), void *data
)
250 static struct ap_info
* ap_ap_add(struct hostapd_iface
*iface
, u8
*addr
)
254 ap
= wpa_zalloc(sizeof(struct ap_info
));
258 /* initialize AP info data */
259 memcpy(ap
->addr
, addr
, ETH_ALEN
);
260 ap_ap_list_add(iface
, ap
);
262 ap_ap_hash_add(iface
, ap
);
263 ap_ap_iter_list_add(iface
, ap
);
265 if (iface
->num_ap
> iface
->conf
->ap_table_max_size
&& ap
!= ap
->prev
) {
266 wpa_printf(MSG_DEBUG
, "Removing the least recently used AP "
267 MACSTR
" from AP table", MAC2STR(ap
->prev
->addr
));
268 if (iface
->conf
->passive_scan_interval
> 0)
269 ap_list_expired_ap(iface
, ap
->prev
);
270 ap_free_ap(iface
, ap
->prev
);
277 void ap_list_process_beacon(struct hostapd_iface
*iface
,
278 struct ieee80211_mgmt
*mgmt
,
279 struct ieee802_11_elems
*elems
,
280 struct hostapd_frame_info
*fi
)
286 if (iface
->conf
->ap_table_max_size
< 1)
289 ap
= ap_get_ap(iface
, mgmt
->bssid
);
291 ap
= ap_ap_add(iface
, mgmt
->bssid
);
293 printf("Failed to allocate AP information entry\n");
299 ap
->beacon_int
= le_to_host16(mgmt
->u
.beacon
.beacon_int
);
300 ap
->capability
= le_to_host16(mgmt
->u
.beacon
.capab_info
);
303 len
= elems
->ssid_len
;
304 if (len
>= sizeof(ap
->ssid
))
305 len
= sizeof(ap
->ssid
) - 1;
306 memcpy(ap
->ssid
, elems
->ssid
, len
);
307 ap
->ssid
[len
] = '\0';
311 memset(ap
->supported_rates
, 0, WLAN_SUPP_RATES_MAX
);
313 if (elems
->supp_rates
) {
314 len
= elems
->supp_rates_len
;
315 if (len
> WLAN_SUPP_RATES_MAX
)
316 len
= WLAN_SUPP_RATES_MAX
;
317 memcpy(ap
->supported_rates
, elems
->supp_rates
, len
);
319 if (elems
->ext_supp_rates
) {
321 if (len
+ elems
->ext_supp_rates_len
> WLAN_SUPP_RATES_MAX
)
322 len2
= WLAN_SUPP_RATES_MAX
- len
;
324 len2
= elems
->ext_supp_rates_len
;
325 memcpy(ap
->supported_rates
+ len
, elems
->ext_supp_rates
, len2
);
328 ap
->wpa
= elems
->wpa_ie
!= NULL
;
330 if (elems
->erp_info
&& elems
->erp_info_len
== 1)
331 ap
->erp
= elems
->erp_info
[0];
335 if (elems
->ds_params
&& elems
->ds_params_len
== 1)
336 ap
->channel
= elems
->ds_params
[0];
338 ap
->channel
= fi
->channel
;
341 time(&ap
->last_beacon
);
343 ap
->phytype
= fi
->phytype
;
344 ap
->ssi_signal
= fi
->ssi_signal
;
345 ap
->datarate
= fi
->datarate
;
349 if (iface
->conf
->passive_scan_interval
> 0)
350 ap_list_new_ap(iface
, ap
);
351 } else if (ap
!= iface
->ap_list
) {
352 /* move AP entry into the beginning of the list so that the
353 * oldest entry is always in the end of the list */
354 ap_ap_list_del(iface
, ap
);
355 ap_ap_list_add(iface
, ap
);
359 ap_list_beacon_olbc(iface
, ap
)) {
360 struct hostapd_data
*hapd
= iface
->bss
[0];
362 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL
,
363 "OLBC AP detected: " MACSTR
" - enable "
364 "protection\n", MAC2STR(ap
->addr
));
365 ieee802_11_set_beacons(hapd
->iface
);
370 static void ap_list_timer(void *eloop_ctx
, void *timeout_ctx
)
372 struct hostapd_iface
*iface
= eloop_ctx
;
376 eloop_register_timeout(10, 0, ap_list_timer
, iface
, NULL
);
383 /* FIX: it looks like jkm-Purina ended up in busy loop in this
384 * function. Apparently, something can still cause a loop in the AP
387 while (iface
->ap_list
) {
388 ap
= iface
->ap_list
->prev
;
389 if (ap
->last_beacon
+ iface
->conf
->ap_table_expiration_time
>=
393 if (iface
->conf
->passive_scan_interval
> 0)
394 ap_list_expired_ap(iface
, ap
);
395 ap_free_ap(iface
, ap
);
402 if (ap_list_beacon_olbc(iface
, ap
)) {
409 struct hostapd_data
*hapd
= iface
->bss
[0];
410 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL
,
411 "OLBC not detected anymore\n");
413 ieee802_11_set_beacons(hapd
->iface
);
419 int ap_list_init(struct hostapd_iface
*iface
)
421 eloop_register_timeout(10, 0, ap_list_timer
, iface
, NULL
);
426 void ap_list_deinit(struct hostapd_iface
*iface
)
428 eloop_cancel_timeout(ap_list_timer
, iface
, NULL
);
429 hostapd_free_aps(iface
);
433 int ap_list_reconfig(struct hostapd_iface
*iface
,
434 struct hostapd_config
*oldconf
)
439 if (iface
->conf
->ap_table_max_size
== oldconf
->ap_table_max_size
&&
440 iface
->conf
->ap_table_expiration_time
==
441 oldconf
->ap_table_expiration_time
)
446 while (iface
->ap_list
) {
447 ap
= iface
->ap_list
->prev
;
448 if (iface
->num_ap
<= iface
->conf
->ap_table_max_size
&&
449 ap
->last_beacon
+ iface
->conf
->ap_table_expiration_time
>=
453 if (iface
->conf
->passive_scan_interval
> 0)
454 ap_list_expired_ap(iface
, iface
->ap_list
->prev
);
455 ap_free_ap(iface
, iface
->ap_list
->prev
);