Adjust for symbol name changes.
[dragonfly.git] / contrib / hostapd-0.4.9 / sta_info.c
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>
5  *
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.
9  *
10  * Alternatively, this software may be distributed under the terms of BSD
11  * license.
12  *
13  * See README and COPYING for more details.
14  */
15
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>
22
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"
35
36
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)
41 {
42         struct sta_info *sta;
43
44         for (sta = hapd->sta_list; sta; sta = sta->next) {
45                 if (cb(hapd, sta, ctx))
46                         return 1;
47         }
48
49         return 0;
50 }
51
52
53 struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
54 {
55         struct sta_info *s;
56
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;
61 }
62
63
64 static void ap_sta_list_del(hostapd *hapd, struct sta_info *sta)
65 {
66         struct sta_info *tmp;
67
68         if (hapd->sta_list == sta) {
69                 hapd->sta_list = sta->next;
70                 return;
71         }
72
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;
81 }
82
83
84 void ap_sta_hash_add(hostapd *hapd, struct sta_info *sta)
85 {
86         sta->hnext = hapd->sta_hash[STA_HASH(sta->addr)];
87         hapd->sta_hash[STA_HASH(sta->addr)] = sta;
88 }
89
90
91 static void ap_sta_hash_del(hostapd *hapd, struct sta_info *sta)
92 {
93         struct sta_info *s;
94
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;
100         }
101
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));
109 }
110
111
112 void ap_free_sta(hostapd *hapd, struct sta_info *sta)
113 {
114         accounting_sta_stop(hapd, sta);
115         if (!(sta->flags & WLAN_STA_PREAUTH))
116                 hostapd_sta_remove(hapd, sta->addr);
117
118         ap_sta_hash_del(hapd, sta);
119         ap_sta_list_del(hapd, sta);
120
121         if (sta->aid > 0)
122                 hapd->sta_aid[sta->aid - 1] = NULL;
123
124         hapd->num_sta--;
125         eloop_cancel_timeout(ap_handle_timer, hapd, sta);
126
127         ieee802_1x_free_station(sta);
128         wpa_free_station(sta);
129         radius_client_flush_auth(hapd->radius, sta->addr);
130
131         if (sta->last_assoc_req)
132                 free(sta->last_assoc_req);
133
134         free(sta->challenge);
135         free(sta->wpa_ie);
136
137         free(sta);
138 }
139
140
141 void hostapd_free_stas(hostapd *hapd)
142 {
143         struct sta_info *sta, *prev;
144
145         sta = hapd->sta_list;
146
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);
152         }
153 }
154
155
156 void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
157 {
158         hostapd *hapd = eloop_ctx;
159         struct sta_info *sta = timeout_ctx;
160         unsigned long next_time = 0;
161
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;
168         }
169
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;
189                 }
190         }
191
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;
201         }
202
203         if (next_time) {
204                 eloop_register_timeout(next_time, 0, ap_handle_timer, hapd,
205                                        sta);
206                 return;
207         }
208
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;
214
215                 HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
216                               "  Polling STA with data frame\n");
217                 sta->flags |= WLAN_STA_PENDING_POLL;
218
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);
230
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;
235
236                 printf("  Sending %s info to STA " MACSTR "\n",
237                        deauth ? "deauthentication" : "disassociation",
238                        MAC2STR(sta->addr));
239
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);
247                 }
248         }
249
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;
281         }
282 }
283
284
285 void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
286 {
287         hostapd *hapd = eloop_ctx;
288         struct sta_info *sta = timeout_ctx;
289
290         if (!(sta->flags & WLAN_STA_AUTH))
291                 return;
292
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);
300 }
301
302
303 void ap_sta_session_timeout(hostapd *hapd, struct sta_info *sta,
304                             u32 session_timeout)
305 {
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);
312 }
313
314
315 void ap_sta_no_session_timeout(hostapd *hapd, struct sta_info *sta)
316 {
317         eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
318 }
319
320
321 struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
322 {
323         struct sta_info *sta;
324
325         sta = ap_get_sta(hapd, addr);
326         if (sta)
327                 return sta;
328
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;
335         }
336
337         sta = (struct sta_info *) malloc(sizeof(struct sta_info));
338         if (sta == NULL) {
339                 printf("  malloc failed\n");
340                 return NULL;
341         }
342         memset(sta, 0, sizeof(struct sta_info));
343         sta->acct_interim_interval = hapd->conf->radius->acct_interim_interval;
344
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);
353
354         return sta;
355 }