Fix IEEE 802.11r key derivation function to match with the standard
[wpasupplicant] / hostapd / drv_callbacks.c
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
15 #include "includes.h"
16
17 #include "hostapd.h"
18 #include "driver_i.h"
19 #include "ieee802_11.h"
20 #include "radius/radius.h"
21 #include "sta_info.h"
22 #include "accounting.h"
23 #include "tkip_countermeasures.h"
24 #include "ieee802_1x.h"
25 #include "wpa.h"
26 #include "iapp.h"
27 #include "wme.h"
28
29
30 struct prune_data {
31         struct hostapd_data *hapd;
32         const u8 *addr;
33 };
34
35 static int prune_associations(struct hostapd_iface *iface, void *ctx)
36 {
37         struct prune_data *data = ctx;
38         struct sta_info *osta;
39         struct hostapd_data *ohapd;
40         size_t j;
41
42         for (j = 0; j < iface->num_bss; j++) {
43                 ohapd = iface->bss[j];
44                 if (ohapd == data->hapd)
45                         continue;
46                 osta = ap_get_sta(ohapd, data->addr);
47                 if (!osta)
48                         continue;
49
50                 ap_sta_disassociate(ohapd, osta, WLAN_REASON_UNSPECIFIED);
51         }
52
53         return 0;
54 }
55
56 /**
57  * hostapd_prune_associations - Remove extraneous associations
58  * @hapd: Pointer to BSS data for the most recent association
59  * @sta: Pointer to the associated STA data
60  *
61  * This function looks through all radios and BSS's for previous
62  * (stale) associations of STA. If any are found they are removed.
63  */
64 static void hostapd_prune_associations(struct hostapd_data *hapd,
65                                        struct sta_info *sta)
66 {
67         struct prune_data data;
68         data.hapd = hapd;
69         data.addr = sta->addr;
70         hostapd_for_each_interface(prune_associations, &data);
71 }
72
73
74 /**
75  * hostapd_new_assoc_sta - Notify that a new station associated with the AP
76  * @hapd: Pointer to BSS data
77  * @sta: Pointer to the associated STA data
78  * @reassoc: 1 to indicate this was a re-association; 0 = first association
79  *
80  * This function will be called whenever a station associates with the AP. It
81  * can be called from ieee802_11.c for drivers that export MLME to hostapd and
82  * from driver_*.c for drivers that take care of management frames (IEEE 802.11
83  * authentication and association) internally.
84  */
85 void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
86                            int reassoc)
87 {
88         if (hapd->tkip_countermeasures) {
89                 hostapd_sta_deauth(hapd, sta->addr,
90                                    WLAN_REASON_MICHAEL_MIC_FAILURE);
91                 return;
92         }
93
94         hostapd_prune_associations(hapd, sta);
95
96         /* IEEE 802.11F (IAPP) */
97         if (hapd->conf->ieee802_11f)
98                 iapp_new_station(hapd->iapp, sta);
99
100         /* Start accounting here, if IEEE 802.1X and WPA are not used.
101          * IEEE 802.1X/WPA code will start accounting after the station has
102          * been authorized. */
103         if (!hapd->conf->ieee802_1x && !hapd->conf->wpa)
104                 accounting_sta_start(hapd, sta);
105
106         hostapd_wmm_sta_config(hapd, sta);
107
108         /* Start IEEE 802.1X authentication process for new stations */
109         ieee802_1x_new_station(hapd, sta);
110         if (reassoc) {
111                 if (sta->auth_alg != WLAN_AUTH_FT &&
112                     !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)))
113                         wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH);
114         } else
115                 wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
116 }
117
118
119 void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
120                        const u8 *buf, size_t len, int ack)
121 {
122         struct sta_info *sta;
123
124         sta = ap_get_sta(hapd, addr);
125         if (sta && sta->flags & WLAN_STA_PENDING_POLL) {
126                 wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending "
127                            "activity poll", MAC2STR(sta->addr),
128                            ack ? "ACKed" : "did not ACK");
129                 if (ack)
130                         sta->flags &= ~WLAN_STA_PENDING_POLL;
131         }
132         if (sta)
133                 ieee802_1x_tx_status(hapd, sta, buf, len, ack);
134 }
135
136
137 void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd, const u8 *addr)
138 {
139         struct sta_info *sta;
140
141         sta = ap_get_sta(hapd, addr);
142         if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
143                 wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated "
144                            "STA " MACSTR, MAC2STR(addr));
145                 if (sta && (sta->flags & WLAN_STA_AUTH))
146                         hostapd_sta_disassoc(
147                                 hapd, addr,
148                                 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
149                 else
150                         hostapd_sta_deauth(
151                                 hapd, addr,
152                                 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
153         }
154 }
155
156
157 int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
158                         const u8 *ie, size_t ielen)
159 {
160         struct sta_info *sta;
161         int new_assoc, res;
162
163         hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
164                        HOSTAPD_LEVEL_INFO, "associated");
165
166         sta = ap_get_sta(hapd, addr);
167         if (sta) {
168                 accounting_sta_stop(hapd, sta);
169         } else {
170                 sta = ap_sta_add(hapd, addr);
171                 if (sta == NULL)
172                         return -1;
173         }
174         sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
175
176         if (hapd->conf->wpa) {
177                 if (ie == NULL || ielen == 0) {
178                         if (hapd->conf->wps_state) {
179                                 wpa_printf(MSG_DEBUG, "STA did not include "
180                                            "WPA/RSN IE in (Re)Association "
181                                            "Request - possible WPS use");
182                                 sta->flags |= WLAN_STA_MAYBE_WPS;
183                                 goto skip_wpa_check;
184                         }
185
186                         wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
187                         return -1;
188                 }
189                 if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
190                     os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
191                         sta->flags |= WLAN_STA_WPS;
192                         goto skip_wpa_check;
193                 }
194
195                 if (sta->wpa_sm == NULL)
196                         sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
197                                                         sta->addr);
198                 if (sta->wpa_sm == NULL) {
199                         wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
200                                    "machine");
201                         return -1;
202                 }
203                 res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
204                                           ie, ielen, NULL, 0);
205                 if (res != WPA_IE_OK) {
206                         wpa_printf(MSG_DEBUG, "WPA/RSN information element "
207                                    "rejected? (res %u)", res);
208                         wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
209                         return -1;
210                 }
211         } else if (hapd->conf->wps_state) {
212                 if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 &&
213                     os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
214                         sta->flags |= WLAN_STA_WPS;
215                 } else
216                         sta->flags |= WLAN_STA_MAYBE_WPS;
217         }
218 skip_wpa_check:
219
220         new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
221         sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
222         wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
223
224         hostapd_new_assoc_sta(hapd, sta, !new_assoc);
225
226         ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
227
228         return 0;
229 }
230
231
232 void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
233 {
234         struct sta_info *sta;
235
236         hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
237                        HOSTAPD_LEVEL_INFO, "disassociated");
238
239         sta = ap_get_sta(hapd, addr);
240         if (sta == NULL) {
241                 wpa_printf(MSG_DEBUG, "Disassociation notification for "
242                            "unknown STA " MACSTR, MAC2STR(addr));
243                 return;
244         }
245
246         sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
247         wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
248         sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
249         ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
250         ap_free_sta(hapd, sta);
251 }
252
253
254 void hostapd_eapol_receive(struct hostapd_data *hapd, const u8 *sa,
255                            const u8 *buf, size_t len)
256 {
257         ieee802_1x_receive(hapd, sa, buf, len);
258 }
259
260
261 #ifdef NEED_MLME
262 void hostapd_mgmt_rx(struct hostapd_data *hapd, u8 *buf, size_t len,
263                      u16 stype, struct hostapd_frame_info *fi)
264 {
265         ieee802_11_mgmt(hapd, buf, len, stype, fi);
266 }
267
268
269 void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, u8 *buf, size_t len,
270                         u16 stype, int ok)
271 {
272         ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
273 }
274 #endif /* NEED_MLME */
275
276
277 void hostapd_michael_mic_failure(struct hostapd_data *hapd, const u8 *addr)
278 {
279         michael_mic_failure(hapd, addr, 1);
280 }