Import of hostapd 0.4.9
[dragonfly.git] / contrib / hostapd-0.4.9 / sta_info.c
blob9eb0bca2e36781c013e5e13a8e686a70bdefad46
1 /*
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
11 * license.
13 * See README and COPYING for more details.
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <netinet/in.h>
20 #include <sys/types.h>
21 #include <sys/socket.h>
23 #include "hostapd.h"
24 #include "sta_info.h"
25 #include "eloop.h"
26 #include "accounting.h"
27 #include "ieee802_1x.h"
28 #include "ieee802_11.h"
29 #include "radius.h"
30 #include "eapol_sm.h"
31 #include "wpa.h"
32 #include "radius_client.h"
33 #include "driver.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,
39 void *ctx),
40 void *ctx)
42 struct sta_info *sta;
44 for (sta = hapd->sta_list; sta; sta = sta->next) {
45 if (cb(hapd, sta, ctx))
46 return 1;
49 return 0;
53 struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
55 struct sta_info *s;
57 s = hapd->sta_hash[STA_HASH(sta)];
58 while (s != NULL && memcmp(s->addr, sta, 6) != 0)
59 s = s->hnext;
60 return s;
64 static void ap_sta_list_del(hostapd *hapd, struct sta_info *sta)
66 struct sta_info *tmp;
68 if (hapd->sta_list == sta) {
69 hapd->sta_list = sta->next;
70 return;
73 tmp = hapd->sta_list;
74 while (tmp != NULL && tmp->next != sta)
75 tmp = tmp->next;
76 if (tmp == NULL) {
77 printf("Could not remove STA " MACSTR " from list.\n",
78 MAC2STR(sta->addr));
79 } else
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)
93 struct sta_info *s;
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;
99 return;
102 while (s->hnext != NULL && memcmp(s->hnext->addr, sta->addr, 6) != 0)
103 s = s->hnext;
104 if (s->hnext != NULL)
105 s->hnext = s->hnext->hnext;
106 else
107 printf("AP: could not remove STA " MACSTR " from hash table\n",
108 MAC2STR(sta->addr));
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);
121 if (sta->aid > 0)
122 hapd->sta_aid[sta->aid - 1] = NULL;
124 hapd->num_sta--;
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);
135 free(sta->wpa_ie);
137 free(sta);
141 void hostapd_free_stas(hostapd *hapd)
143 struct sta_info *sta, *prev;
145 sta = hapd->sta_list;
147 while (sta) {
148 prev = sta;
149 sta = sta->next;
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);
167 return;
170 if ((sta->flags & WLAN_STA_ASSOC) &&
171 (sta->timeout_next == STA_NULLFUNC ||
172 sta->timeout_next == STA_DISASSOC)) {
173 int inactive_sec;
174 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
175 "Checking STA " MACSTR " inactivity:\n",
176 MAC2STR(sta->addr));
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",
181 MAC2STR(sta->addr));
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;
203 if (next_time) {
204 eloop_register_timeout(next_time, 0, ap_handle_timer, hapd,
205 sta);
206 return;
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
212 * is ACKed */
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
221 * received for it */
222 memset(&hdr, 0, sizeof(hdr));
223 hdr.frame_control =
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",
238 MAC2STR(sta->addr));
240 if (deauth) {
241 hostapd_sta_deauth(hapd, sta->addr,
242 WLAN_REASON_PREV_AUTH_NOT_VALID);
243 } else {
244 hostapd_sta_disassoc(
245 hapd, sta->addr,
246 WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
250 switch (sta->timeout_next) {
251 case STA_NULLFUNC:
252 sta->timeout_next = STA_DISASSOC;
253 eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer,
254 hapd, sta);
255 break;
256 case STA_DISASSOC:
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 "
266 "inactivity");
267 sta->timeout_next = STA_DEAUTH;
268 eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
269 hapd, sta);
270 break;
271 case STA_DEAUTH:
272 case STA_REMOVE:
273 hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
274 HOSTAPD_LEVEL_INFO, "deauthenticated due to "
275 "inactivity");
276 if (!sta->acct_terminate_cause)
277 sta->acct_terminate_cause =
278 RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
279 ap_free_sta(hapd, sta);
280 break;
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))
291 return;
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 "
296 "session timeout");
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,
304 u32 session_timeout)
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,
311 hapd, sta);
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);
326 if (sta)
327 return sta;
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);
334 return NULL;
337 sta = (struct sta_info *) malloc(sizeof(struct sta_info));
338 if (sta == NULL) {
339 printf(" malloc failed\n");
340 return NULL;
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,
347 hapd, sta);
348 memcpy(sta->addr, addr, ETH_ALEN);
349 sta->next = hapd->sta_list;
350 hapd->sta_list = sta;
351 hapd->num_sta++;
352 ap_sta_hash_add(hapd, sta);
354 return sta;