2 * Host AP (software wireless LAN access point) user space daemon for
3 * Host AP kernel driver / Station table
4 * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * Alternatively, this software may be distributed under the terms of BSD
13 * See README and COPYING for more details.
19 #include <netinet/in.h>
20 #include <sys/types.h>
21 #include <sys/socket.h>
26 #include "accounting.h"
27 #include "ieee802_1x.h"
28 #include "ieee802_11.h"
32 #include "radius_client.h"
34 #include "hostap_common.h"
37 int ap_for_each_sta(struct hostapd_data
*hapd
,
38 int (*cb
)(struct hostapd_data
*hapd
, struct sta_info
*sta
,
44 for (sta
= hapd
->sta_list
; sta
; sta
= sta
->next
) {
45 if (cb(hapd
, sta
, ctx
))
53 struct sta_info
* ap_get_sta(struct hostapd_data
*hapd
, const u8
*sta
)
57 s
= hapd
->sta_hash
[STA_HASH(sta
)];
58 while (s
!= NULL
&& memcmp(s
->addr
, sta
, 6) != 0)
64 static void ap_sta_list_del(hostapd
*hapd
, struct sta_info
*sta
)
68 if (hapd
->sta_list
== sta
) {
69 hapd
->sta_list
= sta
->next
;
74 while (tmp
!= NULL
&& tmp
->next
!= sta
)
77 printf("Could not remove STA " MACSTR
" from list.\n",
80 tmp
->next
= sta
->next
;
84 void ap_sta_hash_add(hostapd
*hapd
, struct sta_info
*sta
)
86 sta
->hnext
= hapd
->sta_hash
[STA_HASH(sta
->addr
)];
87 hapd
->sta_hash
[STA_HASH(sta
->addr
)] = sta
;
91 static void ap_sta_hash_del(hostapd
*hapd
, struct sta_info
*sta
)
95 s
= hapd
->sta_hash
[STA_HASH(sta
->addr
)];
96 if (s
== NULL
) return;
97 if (memcmp(s
->addr
, sta
->addr
, 6) == 0) {
98 hapd
->sta_hash
[STA_HASH(sta
->addr
)] = s
->hnext
;
102 while (s
->hnext
!= NULL
&& memcmp(s
->hnext
->addr
, sta
->addr
, 6) != 0)
104 if (s
->hnext
!= NULL
)
105 s
->hnext
= s
->hnext
->hnext
;
107 printf("AP: could not remove STA " MACSTR
" from hash table\n",
112 void ap_free_sta(hostapd
*hapd
, struct sta_info
*sta
)
114 accounting_sta_stop(hapd
, sta
);
115 if (!(sta
->flags
& WLAN_STA_PREAUTH
))
116 hostapd_sta_remove(hapd
, sta
->addr
);
118 ap_sta_hash_del(hapd
, sta
);
119 ap_sta_list_del(hapd
, sta
);
122 hapd
->sta_aid
[sta
->aid
- 1] = NULL
;
125 eloop_cancel_timeout(ap_handle_timer
, hapd
, sta
);
127 ieee802_1x_free_station(sta
);
128 wpa_free_station(sta
);
129 radius_client_flush_auth(hapd
->radius
, sta
->addr
);
131 if (sta
->last_assoc_req
)
132 free(sta
->last_assoc_req
);
134 free(sta
->challenge
);
141 void hostapd_free_stas(hostapd
*hapd
)
143 struct sta_info
*sta
, *prev
;
145 sta
= hapd
->sta_list
;
150 printf("Removing station " MACSTR
"\n", MAC2STR(prev
->addr
));
151 ap_free_sta(hapd
, prev
);
156 void ap_handle_timer(void *eloop_ctx
, void *timeout_ctx
)
158 hostapd
*hapd
= eloop_ctx
;
159 struct sta_info
*sta
= timeout_ctx
;
160 unsigned long next_time
= 0;
162 if (sta
->timeout_next
== STA_REMOVE
) {
163 hostapd_logger(hapd
, sta
->addr
, HOSTAPD_MODULE_IEEE80211
,
164 HOSTAPD_LEVEL_INFO
, "deauthenticated due to "
165 "local deauth request");
166 ap_free_sta(hapd
, sta
);
170 if ((sta
->flags
& WLAN_STA_ASSOC
) &&
171 (sta
->timeout_next
== STA_NULLFUNC
||
172 sta
->timeout_next
== STA_DISASSOC
)) {
174 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL
,
175 "Checking STA " MACSTR
" inactivity:\n",
177 inactive_sec
= hostapd_get_inact_sec(hapd
, sta
->addr
);
178 if (inactive_sec
== -1) {
179 printf(" Could not get station info from kernel "
180 "driver for " MACSTR
".\n",
182 } else if (inactive_sec
< AP_MAX_INACTIVITY
&&
183 sta
->flags
& WLAN_STA_ASSOC
) {
184 /* station activity detected; reset timeout state */
185 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL
,
186 " Station has been active\n");
187 sta
->timeout_next
= STA_NULLFUNC
;
188 next_time
= AP_MAX_INACTIVITY
- inactive_sec
;
192 if ((sta
->flags
& WLAN_STA_ASSOC
) &&
193 sta
->timeout_next
== STA_DISASSOC
&&
194 !(sta
->flags
& WLAN_STA_PENDING_POLL
)) {
195 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL
,
196 " Station has ACKed data poll\n");
197 /* data nullfunc frame poll did not produce TX errors; assume
198 * station ACKed it */
199 sta
->timeout_next
= STA_NULLFUNC
;
200 next_time
= AP_MAX_INACTIVITY
;
204 eloop_register_timeout(next_time
, 0, ap_handle_timer
, hapd
,
209 if (sta
->timeout_next
== STA_NULLFUNC
&&
210 (sta
->flags
& WLAN_STA_ASSOC
)) {
211 /* send data frame to poll STA and check whether this frame
213 struct ieee80211_hdr hdr
;
215 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL
,
216 " Polling STA with data frame\n");
217 sta
->flags
|= WLAN_STA_PENDING_POLL
;
219 /* FIX: WLAN_FC_STYPE_NULLFUNC would be more appropriate, but
220 * it is apparently not retried so TX Exc events are not
222 memset(&hdr
, 0, sizeof(hdr
));
224 IEEE80211_FC(WLAN_FC_TYPE_DATA
, WLAN_FC_STYPE_DATA
);
225 hdr
.frame_control
|= host_to_le16(BIT(1));
226 hdr
.frame_control
|= host_to_le16(WLAN_FC_FROMDS
);
227 memcpy(hdr
.IEEE80211_DA_FROMDS
, sta
->addr
, ETH_ALEN
);
228 memcpy(hdr
.IEEE80211_BSSID_FROMDS
, hapd
->own_addr
, ETH_ALEN
);
229 memcpy(hdr
.IEEE80211_SA_FROMDS
, hapd
->own_addr
, ETH_ALEN
);
231 if (hostapd_send_mgmt_frame(hapd
, &hdr
, sizeof(hdr
), 0) < 0)
232 perror("ap_handle_timer: send");
233 } else if (sta
->timeout_next
!= STA_REMOVE
) {
234 int deauth
= sta
->timeout_next
== STA_DEAUTH
;
236 printf(" Sending %s info to STA " MACSTR
"\n",
237 deauth
? "deauthentication" : "disassociation",
241 hostapd_sta_deauth(hapd
, sta
->addr
,
242 WLAN_REASON_PREV_AUTH_NOT_VALID
);
244 hostapd_sta_disassoc(
246 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY
);
250 switch (sta
->timeout_next
) {
252 sta
->timeout_next
= STA_DISASSOC
;
253 eloop_register_timeout(AP_DISASSOC_DELAY
, 0, ap_handle_timer
,
257 sta
->flags
&= ~WLAN_STA_ASSOC
;
258 ieee802_1x_set_port_enabled(hapd
, sta
, 0);
259 if (!sta
->acct_terminate_cause
)
260 sta
->acct_terminate_cause
=
261 RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT
;
262 accounting_sta_stop(hapd
, sta
);
263 ieee802_1x_free_station(sta
);
264 hostapd_logger(hapd
, sta
->addr
, HOSTAPD_MODULE_IEEE80211
,
265 HOSTAPD_LEVEL_INFO
, "disassociated due to "
267 sta
->timeout_next
= STA_DEAUTH
;
268 eloop_register_timeout(AP_DEAUTH_DELAY
, 0, ap_handle_timer
,
273 hostapd_logger(hapd
, sta
->addr
, HOSTAPD_MODULE_IEEE80211
,
274 HOSTAPD_LEVEL_INFO
, "deauthenticated due to "
276 if (!sta
->acct_terminate_cause
)
277 sta
->acct_terminate_cause
=
278 RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT
;
279 ap_free_sta(hapd
, sta
);
285 void ap_handle_session_timer(void *eloop_ctx
, void *timeout_ctx
)
287 hostapd
*hapd
= eloop_ctx
;
288 struct sta_info
*sta
= timeout_ctx
;
290 if (!(sta
->flags
& WLAN_STA_AUTH
))
293 hostapd_sta_deauth(hapd
, sta
->addr
, WLAN_REASON_PREV_AUTH_NOT_VALID
);
294 hostapd_logger(hapd
, sta
->addr
, HOSTAPD_MODULE_IEEE80211
,
295 HOSTAPD_LEVEL_INFO
, "deauthenticated due to "
297 sta
->acct_terminate_cause
=
298 RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT
;
299 ap_free_sta(hapd
, sta
);
303 void ap_sta_session_timeout(hostapd
*hapd
, struct sta_info
*sta
,
306 hostapd_logger(hapd
, sta
->addr
, HOSTAPD_MODULE_IEEE80211
,
307 HOSTAPD_LEVEL_DEBUG
, "setting session timeout to %d "
308 "seconds", session_timeout
);
309 eloop_cancel_timeout(ap_handle_session_timer
, hapd
, sta
);
310 eloop_register_timeout(session_timeout
, 0, ap_handle_session_timer
,
315 void ap_sta_no_session_timeout(hostapd
*hapd
, struct sta_info
*sta
)
317 eloop_cancel_timeout(ap_handle_session_timer
, hapd
, sta
);
321 struct sta_info
* ap_sta_add(struct hostapd_data
*hapd
, const u8
*addr
)
323 struct sta_info
*sta
;
325 sta
= ap_get_sta(hapd
, addr
);
329 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL
, " New STA\n");
330 if (hapd
->num_sta
>= MAX_STA_COUNT
) {
331 /* FIX: might try to remove some old STAs first? */
332 printf(" no more room for new STAs (%d/%d)\n",
333 hapd
->num_sta
, MAX_STA_COUNT
);
337 sta
= (struct sta_info
*) malloc(sizeof(struct sta_info
));
339 printf(" malloc failed\n");
342 memset(sta
, 0, sizeof(struct sta_info
));
343 sta
->acct_interim_interval
= hapd
->conf
->radius
->acct_interim_interval
;
345 /* initialize STA info data */
346 eloop_register_timeout(AP_MAX_INACTIVITY
, 0, ap_handle_timer
,
348 memcpy(sta
->addr
, addr
, ETH_ALEN
);
349 sta
->next
= hapd
->sta_list
;
350 hapd
->sta_list
= sta
;
352 ap_sta_hash_add(hapd
, sta
);