]> git.ipfire.org Git - thirdparty/hostap.git/blame - src/ap/drv_callbacks.c
Replace hostapd_notif_new_sta() with new driver event, EVENT_NEW_STA
[thirdparty/hostap.git] / src / ap / drv_callbacks.c
CommitLineData
b5b969e9
JM
1/*
2 * hostapd / Callback functions for driver wrappers
3 * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
6226e38d 15#include "utils/includes.h"
b5b969e9 16
6226e38d 17#include "utils/common.h"
b5b969e9 18#include "radius/radius.h"
6e6e8c31 19#include "drivers/driver.h"
81f4f619 20#include "common/ieee802_11_defs.h"
6226e38d
JM
21#include "hostapd.h"
22#include "ieee802_11.h"
23#include "sta_info.h"
24#include "accounting.h"
25#include "tkip_countermeasures.h"
26#include "iapp.h"
27#include "ieee802_1x.h"
28#include "wpa_auth.h"
29#include "wmm.h"
30#include "wps_hostapd.h"
8b06c1ed 31#include "ap_config.h"
b5b969e9
JM
32
33
a70a5d6d 34static int hostapd_notif_new_sta(struct hostapd_data *hapd, const u8 *addr)
05310066
JM
35{
36 struct sta_info *sta = ap_get_sta(hapd, addr);
37 if (sta)
38 return 0;
39
40 wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR
41 " - adding a new STA", MAC2STR(addr));
42 sta = ap_sta_add(hapd, addr);
43 if (sta) {
44 hostapd_new_assoc_sta(hapd, sta, 0);
45 } else {
46 wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR,
47 MAC2STR(addr));
48 return -1;
49 }
50
51 return 0;
52}
53
54
b5b969e9
JM
55int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
56 const u8 *ie, size_t ielen)
57{
58 struct sta_info *sta;
59 int new_assoc, res;
60
61 hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
62 HOSTAPD_LEVEL_INFO, "associated");
63
64 sta = ap_get_sta(hapd, addr);
65 if (sta) {
66 accounting_sta_stop(hapd, sta);
67 } else {
68 sta = ap_sta_add(hapd, addr);
69 if (sta == NULL)
70 return -1;
71 }
72 sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
73
74 if (hapd->conf->wpa) {
75 if (ie == NULL || ielen == 0) {
76 if (hapd->conf->wps_state) {
77 wpa_printf(MSG_DEBUG, "STA did not include "
78 "WPA/RSN IE in (Re)Association "
79 "Request - possible WPS use");
80 sta->flags |= WLAN_STA_MAYBE_WPS;
81 goto skip_wpa_check;
82 }
83
84 wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
85 return -1;
86 }
87 if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
88 os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
89 sta->flags |= WLAN_STA_WPS;
90 goto skip_wpa_check;
91 }
92
93 if (sta->wpa_sm == NULL)
94 sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
95 sta->addr);
96 if (sta->wpa_sm == NULL) {
97 wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
98 "machine");
99 return -1;
100 }
101 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
102 ie, ielen, NULL, 0);
103 if (res != WPA_IE_OK) {
355d36a7 104 int resp;
b5b969e9
JM
105 wpa_printf(MSG_DEBUG, "WPA/RSN information element "
106 "rejected? (res %u)", res);
107 wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
355d36a7
AT
108 if (res == WPA_INVALID_GROUP)
109 resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
110 else if (res == WPA_INVALID_PAIRWISE)
111 resp = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
112 else if (res == WPA_INVALID_AKMP)
113 resp = WLAN_REASON_AKMP_NOT_VALID;
114#ifdef CONFIG_IEEE80211W
115 else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
116 resp = WLAN_REASON_INVALID_IE;
117 else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
118 resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
119#endif /* CONFIG_IEEE80211W */
120 else
121 resp = WLAN_REASON_INVALID_IE;
bdee6fce 122 hapd->drv.sta_disassoc(hapd, sta->addr, resp);
355d36a7 123 ap_free_sta(hapd, sta);
b5b969e9
JM
124 return -1;
125 }
a9aca28b
JM
126 } else if (hapd->conf->wps_state) {
127 if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 &&
128 os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
129 sta->flags |= WLAN_STA_WPS;
130 } else
131 sta->flags |= WLAN_STA_MAYBE_WPS;
b5b969e9
JM
132 }
133skip_wpa_check:
134
135 new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
136 sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
137 wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
138
139 hostapd_new_assoc_sta(hapd, sta, !new_assoc);
140
141 ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
142
143 return 0;
144}
145
146
147void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
148{
149 struct sta_info *sta;
150
151 hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
152 HOSTAPD_LEVEL_INFO, "disassociated");
153
154 sta = ap_get_sta(hapd, addr);
155 if (sta == NULL) {
156 wpa_printf(MSG_DEBUG, "Disassociation notification for "
157 "unknown STA " MACSTR, MAC2STR(addr));
158 return;
159 }
160
161 sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
162 wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
163 sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
164 ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
165 ap_free_sta(hapd, sta);
166}
167
168
169void hostapd_eapol_receive(struct hostapd_data *hapd, const u8 *sa,
170 const u8 *buf, size_t len)
171{
172 ieee802_1x_receive(hapd, sa, buf, len);
173}
174
175
f8b1f695
JM
176struct hostapd_data * hostapd_sta_get_bss(struct hostapd_data *hapd,
177 const u8 *addr)
178{
179 struct hostapd_iface *iface = hapd->iface;
180 size_t j;
181
182 for (j = 0; j < iface->num_bss; j++) {
183 hapd = iface->bss[j];
184 if (ap_get_sta(hapd, addr))
185 return hapd;
186 }
187
188 return NULL;
189}
190
191
192#ifdef HOSTAPD
193
fe6bdb77 194#ifdef NEED_AP_MLME
f8b1f695
JM
195
196static const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
197{
198 u16 fc, type, stype;
199
200 /*
201 * PS-Poll frames are 16 bytes. All other frames are
202 * 24 bytes or longer.
203 */
204 if (len < 16)
205 return NULL;
206
207 fc = le_to_host16(hdr->frame_control);
208 type = WLAN_FC_GET_TYPE(fc);
209 stype = WLAN_FC_GET_STYPE(fc);
210
211 switch (type) {
212 case WLAN_FC_TYPE_DATA:
213 if (len < 24)
214 return NULL;
215 switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
fbbfcbac 216 case WLAN_FC_FROMDS | WLAN_FC_TODS:
f8b1f695
JM
217 case WLAN_FC_TODS:
218 return hdr->addr1;
219 case WLAN_FC_FROMDS:
220 return hdr->addr2;
221 default:
222 return NULL;
223 }
224 case WLAN_FC_TYPE_CTRL:
225 if (stype != WLAN_FC_STYPE_PSPOLL)
226 return NULL;
227 return hdr->addr1;
228 case WLAN_FC_TYPE_MGMT:
229 return hdr->addr3;
230 default:
231 return NULL;
232 }
233}
234
235
236#define HAPD_BROADCAST ((struct hostapd_data *) -1)
237
238static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
239 const u8 *bssid)
240{
241 size_t i;
242
243 if (bssid == NULL)
244 return NULL;
245 if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff &&
246 bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff)
247 return HAPD_BROADCAST;
248
249 for (i = 0; i < iface->num_bss; i++) {
250 if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0)
251 return iface->bss[i];
252 }
253
254 return NULL;
255}
256
257
258static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
0d9fc3d8 259 const u8 *frame, size_t len)
f8b1f695 260{
0d9fc3d8 261 const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) frame;
fbbfcbac 262 u16 fc = le_to_host16(hdr->frame_control);
f8b1f695
JM
263 hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
264 if (hapd == NULL || hapd == HAPD_BROADCAST)
265 return;
266
fbbfcbac
FF
267 ieee802_11_rx_from_unknown(hapd, hdr->addr2,
268 (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
269 (WLAN_FC_TODS | WLAN_FC_FROMDS));
f8b1f695
JM
270}
271
272
2a8b7416 273static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
b5b969e9 274{
4b9841d3 275 struct hostapd_iface *iface = hapd->iface;
b57e086c 276 const struct ieee80211_hdr *hdr;
4b9841d3 277 const u8 *bssid;
2a8b7416 278 struct hostapd_frame_info fi;
4b9841d3 279
2a8b7416
JM
280 hdr = (const struct ieee80211_hdr *) rx_mgmt->frame;
281 bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len);
4b9841d3
JM
282 if (bssid == NULL)
283 return;
284
285 hapd = get_hapd_bssid(iface, bssid);
286 if (hapd == NULL) {
287 u16 fc;
288 fc = le_to_host16(hdr->frame_control);
289
290 /*
291 * Drop frames to unknown BSSIDs except for Beacon frames which
292 * could be used to update neighbor information.
293 */
294 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
295 WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
296 hapd = iface->bss[0];
297 else
298 return;
299 }
300
2a8b7416
JM
301 os_memset(&fi, 0, sizeof(fi));
302 fi.datarate = rx_mgmt->datarate;
303 fi.ssi_signal = rx_mgmt->ssi_signal;
304
4b9841d3
JM
305 if (hapd == HAPD_BROADCAST) {
306 size_t i;
307 for (i = 0; i < iface->num_bss; i++)
2a8b7416
JM
308 ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,
309 rx_mgmt->frame_len, &fi);
4b9841d3 310 } else
2a8b7416 311 ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, &fi);
b5b969e9
JM
312}
313
314
f8b1f695
JM
315static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
316 size_t len, u16 stype, int ok)
b5b969e9 317{
4b9841d3
JM
318 struct ieee80211_hdr *hdr;
319 hdr = (struct ieee80211_hdr *) buf;
320 hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
321 if (hapd == NULL || hapd == HAPD_BROADCAST)
322 return;
b5b969e9
JM
323 ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
324}
f82ef4d8 325
f8b1f695 326#endif /* NEED_AP_MLME */
ad1e68e6
JM
327
328
a0e0d3bb
JM
329static int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa,
330 const u8 *ie, size_t ie_len)
331{
332 size_t i;
333 int ret = 0;
334
335 for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
336 if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
337 sa, ie, ie_len) > 0) {
338 ret = 1;
339 break;
340 }
341 }
342 return ret;
343}
344
345
9646a8ab 346void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
ad1e68e6
JM
347 union wpa_event_data *data)
348{
349 struct hostapd_data *hapd = ctx;
350
351 switch (event) {
352 case EVENT_MICHAEL_MIC_FAILURE:
353 michael_mic_failure(hapd, data->michael_mic_failure.src, 1);
354 break;
355 case EVENT_SCAN_RESULTS:
356 if (hapd->iface->scan_cb)
357 hapd->iface->scan_cb(hapd->iface);
358 break;
08fd8c15 359#ifdef CONFIG_IEEE80211R
f2dab64e 360 case EVENT_FT_RRB_RX:
08fd8c15
JM
361 wpa_ft_rrb_rx(hapd->wpa_auth, data->ft_rrb_rx.src,
362 data->ft_rrb_rx.data, data->ft_rrb_rx.data_len);
363 break;
364#endif /* CONFIG_IEEE80211R */
fcf0f87d
JM
365 case EVENT_WPS_BUTTON_PUSHED:
366 hostapd_wps_button_pushed(hapd);
367 break;
f8b1f695
JM
368#ifdef NEED_AP_MLME
369 case EVENT_TX_STATUS:
370 switch (data->tx_status.type) {
371 case WLAN_FC_TYPE_MGMT:
372 hostapd_mgmt_tx_cb(hapd, data->tx_status.data,
373 data->tx_status.data_len,
374 data->tx_status.stype,
375 data->tx_status.ack);
376 break;
377 case WLAN_FC_TYPE_DATA:
378 hostapd_tx_status(hapd, data->tx_status.dst,
379 data->tx_status.data,
380 data->tx_status.data_len,
381 data->tx_status.ack);
382 break;
383 }
384 break;
385 case EVENT_RX_FROM_UNKNOWN:
0d9fc3d8 386 hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.frame,
f8b1f695
JM
387 data->rx_from_unknown.len);
388 break;
389 case EVENT_RX_MGMT:
2a8b7416 390 hostapd_mgmt_rx(hapd, &data->rx_mgmt);
f8b1f695
JM
391 break;
392#endif /* NEED_AP_MLME */
a0e0d3bb
JM
393 case EVENT_RX_PROBE_REQ:
394 hostapd_probe_req_rx(hapd, data->rx_probe_req.sa,
395 data->rx_probe_req.ie,
396 data->rx_probe_req.ie_len);
397 break;
a70a5d6d
JM
398 case EVENT_NEW_STA:
399 hostapd_notif_new_sta(hapd, data->new_sta.addr);
ad1e68e6
JM
400 default:
401 wpa_printf(MSG_DEBUG, "Unknown event %d", event);
402 break;
403 }
404}
f8b1f695
JM
405
406#endif /* HOSTAPD */