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