]> git.ipfire.org Git - thirdparty/hostap.git/blame - src/ap/drv_callbacks.c
Replace wpa_supplicant_sta_rx() call with driver event
[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
05310066
JM
34int hostapd_notif_new_sta(struct hostapd_data *hapd, const u8 *addr)
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,
259 const struct ieee80211_hdr *hdr,
260 size_t len)
261{
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
b57e086c 273static void hostapd_mgmt_rx(struct hostapd_data *hapd, const u8 *buf,
f8b1f695 274 size_t len, struct hostapd_frame_info *fi)
b5b969e9 275{
4b9841d3 276 struct hostapd_iface *iface = hapd->iface;
b57e086c 277 const struct ieee80211_hdr *hdr;
4b9841d3
JM
278 const u8 *bssid;
279
b57e086c 280 hdr = (const struct ieee80211_hdr *) buf;
4b9841d3
JM
281 bssid = get_hdr_bssid(hdr, len);
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
301 if (hapd == HAPD_BROADCAST) {
302 size_t i;
303 for (i = 0; i < iface->num_bss; i++)
f8b1f695 304 ieee802_11_mgmt(iface->bss[i], buf, len, fi);
4b9841d3 305 } else
f8b1f695 306 ieee802_11_mgmt(hapd, buf, len, fi);
b5b969e9
JM
307}
308
309
f8b1f695
JM
310static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
311 size_t len, u16 stype, int ok)
b5b969e9 312{
4b9841d3
JM
313 struct ieee80211_hdr *hdr;
314 hdr = (struct ieee80211_hdr *) buf;
315 hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
316 if (hapd == NULL || hapd == HAPD_BROADCAST)
317 return;
b5b969e9
JM
318 ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
319}
f82ef4d8 320
f8b1f695 321#endif /* NEED_AP_MLME */
ad1e68e6
JM
322
323
ad1e68e6
JM
324void wpa_supplicant_event(void *ctx, wpa_event_type event,
325 union wpa_event_data *data)
326{
327 struct hostapd_data *hapd = ctx;
328
329 switch (event) {
330 case EVENT_MICHAEL_MIC_FAILURE:
331 michael_mic_failure(hapd, data->michael_mic_failure.src, 1);
332 break;
333 case EVENT_SCAN_RESULTS:
334 if (hapd->iface->scan_cb)
335 hapd->iface->scan_cb(hapd->iface);
336 break;
08fd8c15 337#ifdef CONFIG_IEEE80211R
f2dab64e 338 case EVENT_FT_RRB_RX:
08fd8c15
JM
339 wpa_ft_rrb_rx(hapd->wpa_auth, data->ft_rrb_rx.src,
340 data->ft_rrb_rx.data, data->ft_rrb_rx.data_len);
341 break;
342#endif /* CONFIG_IEEE80211R */
fcf0f87d
JM
343 case EVENT_WPS_BUTTON_PUSHED:
344 hostapd_wps_button_pushed(hapd);
345 break;
f8b1f695
JM
346#ifdef NEED_AP_MLME
347 case EVENT_TX_STATUS:
348 switch (data->tx_status.type) {
349 case WLAN_FC_TYPE_MGMT:
350 hostapd_mgmt_tx_cb(hapd, data->tx_status.data,
351 data->tx_status.data_len,
352 data->tx_status.stype,
353 data->tx_status.ack);
354 break;
355 case WLAN_FC_TYPE_DATA:
356 hostapd_tx_status(hapd, data->tx_status.dst,
357 data->tx_status.data,
358 data->tx_status.data_len,
359 data->tx_status.ack);
360 break;
361 }
362 break;
363 case EVENT_RX_FROM_UNKNOWN:
364 hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.hdr,
365 data->rx_from_unknown.len);
366 break;
367 case EVENT_RX_MGMT:
368 hostapd_mgmt_rx(hapd, data->rx_mgmt.frame,
369 data->rx_mgmt.frame_len, data->rx_mgmt.fi);
370 break;
371#endif /* NEED_AP_MLME */
ad1e68e6
JM
372 default:
373 wpa_printf(MSG_DEBUG, "Unknown event %d", event);
374 break;
375 }
376}
f8b1f695
JM
377
378#endif /* HOSTAPD */
3fed6f25
JM
379
380
cd7d80f3 381int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa,
3fed6f25
JM
382 const u8 *ie, size_t ie_len)
383{
fa16028d 384 size_t i;
cd7d80f3 385 int ret = 0;
fa16028d 386
cd7d80f3
JM
387 for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
388 if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
389 sa, ie, ie_len) > 0) {
390 ret = 1;
391 break;
392 }
393 }
394 return ret;
3fed6f25 395}