]>
Commit | Line | Data |
---|---|---|
11ef8d35 JM |
1 | /* |
2 | * wpa_supplicant - IBSS RSN | |
3 | * Copyright (c) 2009, Jouni Malinen <j@w1.fi> | |
4 | * | |
0f3d578e JM |
5 | * This software may be distributed under the terms of the BSD license. |
6 | * See README for more details. | |
11ef8d35 JM |
7 | */ |
8 | ||
9 | #include "includes.h" | |
10 | ||
11 | #include "common.h" | |
e2d492dd | 12 | #include "l2_packet/l2_packet.h" |
3acb5005 JM |
13 | #include "rsn_supp/wpa.h" |
14 | #include "rsn_supp/wpa_ie.h" | |
71934751 | 15 | #include "ap/wpa_auth.h" |
1057d78e | 16 | #include "wpa_supplicant_i.h" |
ea038e0d | 17 | #include "driver_i.h" |
11ef8d35 JM |
18 | #include "ibss_rsn.h" |
19 | ||
20 | ||
fa7187bf AQ |
21 | static struct ibss_rsn_peer * ibss_rsn_get_peer(struct ibss_rsn *ibss_rsn, |
22 | const u8 *addr) | |
23 | { | |
24 | struct ibss_rsn_peer *peer; | |
25 | ||
26 | for (peer = ibss_rsn->peers; peer; peer = peer->next) | |
27 | if (os_memcmp(addr, peer->addr, ETH_ALEN) == 0) | |
28 | break; | |
29 | return peer; | |
30 | } | |
31 | ||
32 | ||
11ef8d35 JM |
33 | static void ibss_rsn_free(struct ibss_rsn_peer *peer) |
34 | { | |
35 | wpa_auth_sta_deinit(peer->auth); | |
36 | wpa_sm_deinit(peer->supp); | |
37 | os_free(peer); | |
38 | } | |
39 | ||
40 | ||
71934751 | 41 | static void supp_set_state(void *ctx, enum wpa_states state) |
3146b2b9 JM |
42 | { |
43 | struct ibss_rsn_peer *peer = ctx; | |
44 | peer->supp_state = state; | |
45 | } | |
46 | ||
47 | ||
f385833b XC |
48 | static enum wpa_states supp_get_state(void *ctx) |
49 | { | |
50 | struct ibss_rsn_peer *peer = ctx; | |
51 | return peer->supp_state; | |
52 | } | |
53 | ||
54 | ||
11ef8d35 JM |
55 | static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf, |
56 | size_t len) | |
57 | { | |
e2d492dd JM |
58 | struct ibss_rsn_peer *peer = ctx; |
59 | struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s; | |
11ef8d35 JM |
60 | |
61 | wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x " | |
62 | "len=%lu)", | |
63 | __func__, MAC2STR(dest), proto, (unsigned long) len); | |
64 | ||
e2d492dd JM |
65 | if (wpa_s->l2) |
66 | return l2_packet_send(wpa_s->l2, dest, proto, buf, len); | |
11ef8d35 | 67 | |
e2d492dd | 68 | return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len); |
11ef8d35 JM |
69 | } |
70 | ||
71 | ||
72 | static u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data, | |
73 | u16 data_len, size_t *msg_len, void **data_pos) | |
74 | { | |
75 | struct ieee802_1x_hdr *hdr; | |
76 | ||
77 | wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)", | |
78 | __func__, type, data_len); | |
79 | ||
80 | *msg_len = sizeof(*hdr) + data_len; | |
81 | hdr = os_malloc(*msg_len); | |
82 | if (hdr == NULL) | |
83 | return NULL; | |
84 | ||
85 | hdr->version = 2; | |
86 | hdr->type = type; | |
87 | hdr->length = host_to_be16(data_len); | |
88 | ||
89 | if (data) | |
90 | os_memcpy(hdr + 1, data, data_len); | |
91 | else | |
92 | os_memset(hdr + 1, 0, data_len); | |
93 | ||
94 | if (data_pos) | |
95 | *data_pos = hdr + 1; | |
96 | ||
97 | return (u8 *) hdr; | |
98 | } | |
99 | ||
100 | ||
101 | static int supp_get_beacon_ie(void *ctx) | |
102 | { | |
4691fc7b JM |
103 | struct ibss_rsn_peer *peer = ctx; |
104 | ||
11ef8d35 | 105 | wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); |
4691fc7b JM |
106 | /* TODO: get correct RSN IE */ |
107 | return wpa_sm_set_ap_rsn_ie(peer->supp, | |
108 | (u8 *) "\x30\x14\x01\x00" | |
109 | "\x00\x0f\xac\x04" | |
110 | "\x01\x00\x00\x0f\xac\x04" | |
111 | "\x01\x00\x00\x0f\xac\x02" | |
112 | "\x00\x00", 22); | |
11ef8d35 JM |
113 | } |
114 | ||
115 | ||
71934751 | 116 | static int supp_set_key(void *ctx, enum wpa_alg alg, |
11ef8d35 JM |
117 | const u8 *addr, int key_idx, int set_tx, |
118 | const u8 *seq, size_t seq_len, | |
119 | const u8 *key, size_t key_len) | |
120 | { | |
98f14041 JM |
121 | struct ibss_rsn_peer *peer = ctx; |
122 | ||
a486c0c7 JM |
123 | wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d " |
124 | "set_tx=%d)", | |
125 | __func__, alg, MAC2STR(addr), key_idx, set_tx); | |
126 | wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len); | |
127 | wpa_hexdump_key(MSG_DEBUG, "SUPP: set_key - key", key, key_len); | |
128 | ||
98f14041 JM |
129 | if (key_idx == 0) { |
130 | /* | |
131 | * In IBSS RSN, the pairwise key from the 4-way handshake | |
132 | * initiated by the peer with highest MAC address is used. | |
133 | */ | |
134 | if (os_memcmp(peer->ibss_rsn->wpa_s->own_addr, peer->addr, | |
a486c0c7 JM |
135 | ETH_ALEN) > 0) { |
136 | wpa_printf(MSG_DEBUG, "SUPP: Do not use this PTK"); | |
98f14041 | 137 | return 0; |
a486c0c7 | 138 | } |
98f14041 JM |
139 | } |
140 | ||
4a26df71 | 141 | if (is_broadcast_ether_addr(addr)) |
89c38e32 | 142 | addr = peer->addr; |
98f14041 JM |
143 | return wpa_drv_set_key(peer->ibss_rsn->wpa_s, alg, addr, key_idx, |
144 | set_tx, seq, seq_len, key, key_len); | |
11ef8d35 JM |
145 | } |
146 | ||
147 | ||
3146b2b9 JM |
148 | static void * supp_get_network_ctx(void *ctx) |
149 | { | |
150 | struct ibss_rsn_peer *peer = ctx; | |
151 | return wpa_supplicant_get_ssid(peer->ibss_rsn->wpa_s); | |
152 | } | |
153 | ||
154 | ||
11ef8d35 JM |
155 | static int supp_mlme_setprotection(void *ctx, const u8 *addr, |
156 | int protection_type, int key_type) | |
157 | { | |
158 | wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d " | |
159 | "key_type=%d)", | |
160 | __func__, MAC2STR(addr), protection_type, key_type); | |
161 | return 0; | |
162 | } | |
163 | ||
164 | ||
165 | static void supp_cancel_auth_timeout(void *ctx) | |
166 | { | |
167 | wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); | |
168 | } | |
169 | ||
170 | ||
89c38e32 JM |
171 | static void supp_deauthenticate(void * ctx, int reason_code) |
172 | { | |
173 | wpa_printf(MSG_DEBUG, "SUPP: %s (TODO)", __func__); | |
174 | } | |
175 | ||
176 | ||
19df9b07 JM |
177 | static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr, |
178 | const u8 *psk) | |
11ef8d35 JM |
179 | { |
180 | struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx)); | |
181 | if (ctx == NULL) | |
182 | return -1; | |
183 | ||
184 | ctx->ctx = peer; | |
0f057fb2 | 185 | ctx->msg_ctx = peer->ibss_rsn->wpa_s; |
3146b2b9 | 186 | ctx->set_state = supp_set_state; |
f385833b | 187 | ctx->get_state = supp_get_state; |
11ef8d35 JM |
188 | ctx->ether_send = supp_ether_send; |
189 | ctx->get_beacon_ie = supp_get_beacon_ie; | |
190 | ctx->alloc_eapol = supp_alloc_eapol; | |
191 | ctx->set_key = supp_set_key; | |
3146b2b9 | 192 | ctx->get_network_ctx = supp_get_network_ctx; |
11ef8d35 JM |
193 | ctx->mlme_setprotection = supp_mlme_setprotection; |
194 | ctx->cancel_auth_timeout = supp_cancel_auth_timeout; | |
89c38e32 | 195 | ctx->deauthenticate = supp_deauthenticate; |
11ef8d35 JM |
196 | peer->supp = wpa_sm_init(ctx); |
197 | if (peer->supp == NULL) { | |
198 | wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed"); | |
199 | return -1; | |
200 | } | |
201 | ||
202 | wpa_sm_set_own_addr(peer->supp, own_addr); | |
203 | wpa_sm_set_param(peer->supp, WPA_PARAM_RSN_ENABLED, 1); | |
204 | wpa_sm_set_param(peer->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN); | |
205 | wpa_sm_set_param(peer->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP); | |
206 | wpa_sm_set_param(peer->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP); | |
207 | wpa_sm_set_param(peer->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK); | |
208 | wpa_sm_set_pmk(peer->supp, psk, PMK_LEN); | |
209 | ||
11ef8d35 JM |
210 | peer->supp_ie_len = sizeof(peer->supp_ie); |
211 | if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie, | |
212 | &peer->supp_ie_len) < 0) { | |
213 | wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()" | |
214 | " failed"); | |
215 | return -1; | |
216 | } | |
11ef8d35 JM |
217 | |
218 | wpa_sm_notify_assoc(peer->supp, peer->addr); | |
219 | ||
220 | return 0; | |
221 | } | |
222 | ||
223 | ||
224 | static void auth_logger(void *ctx, const u8 *addr, logger_level level, | |
225 | const char *txt) | |
226 | { | |
227 | if (addr) | |
228 | wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s", | |
229 | MAC2STR(addr), txt); | |
230 | else | |
231 | wpa_printf(MSG_DEBUG, "AUTH: %s", txt); | |
232 | } | |
233 | ||
234 | ||
235 | static const u8 * auth_get_psk(void *ctx, const u8 *addr, const u8 *prev_psk) | |
236 | { | |
237 | struct ibss_rsn *ibss_rsn = ctx; | |
238 | wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)", | |
239 | __func__, MAC2STR(addr), prev_psk); | |
240 | if (prev_psk) | |
241 | return NULL; | |
242 | return ibss_rsn->psk; | |
243 | } | |
244 | ||
245 | ||
246 | static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data, | |
247 | size_t data_len, int encrypt) | |
248 | { | |
da3c6a5e JM |
249 | struct ibss_rsn *ibss_rsn = ctx; |
250 | struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s; | |
11ef8d35 JM |
251 | |
252 | wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu " | |
253 | "encrypt=%d)", | |
254 | __func__, MAC2STR(addr), (unsigned long) data_len, encrypt); | |
255 | ||
e2d492dd JM |
256 | if (wpa_s->l2) |
257 | return l2_packet_send(wpa_s->l2, addr, ETH_P_EAPOL, data, | |
258 | data_len); | |
11ef8d35 | 259 | |
e2d492dd | 260 | return wpa_drv_send_eapol(wpa_s, addr, ETH_P_EAPOL, data, data_len); |
11ef8d35 JM |
261 | } |
262 | ||
263 | ||
71934751 JM |
264 | static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, |
265 | const u8 *addr, int idx, u8 *key, size_t key_len) | |
98f14041 JM |
266 | { |
267 | struct ibss_rsn *ibss_rsn = ctx; | |
268 | u8 seq[6]; | |
98f14041 JM |
269 | |
270 | os_memset(seq, 0, sizeof(seq)); | |
a486c0c7 JM |
271 | |
272 | if (addr) { | |
273 | wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d addr=" MACSTR | |
274 | " key_idx=%d)", | |
275 | __func__, alg, MAC2STR(addr), idx); | |
276 | } else { | |
277 | wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d key_idx=%d)", | |
278 | __func__, alg, idx); | |
279 | } | |
280 | wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len); | |
281 | ||
98f14041 JM |
282 | if (idx == 0) { |
283 | /* | |
284 | * In IBSS RSN, the pairwise key from the 4-way handshake | |
285 | * initiated by the peer with highest MAC address is used. | |
286 | */ | |
a416fb47 JM |
287 | if (addr == NULL || |
288 | os_memcmp(ibss_rsn->wpa_s->own_addr, addr, ETH_ALEN) < 0) { | |
a486c0c7 | 289 | wpa_printf(MSG_DEBUG, "AUTH: Do not use this PTK"); |
98f14041 | 290 | return 0; |
a486c0c7 | 291 | } |
98f14041 JM |
292 | } |
293 | ||
294 | return wpa_drv_set_key(ibss_rsn->wpa_s, alg, addr, idx, | |
295 | 1, seq, 6, key, key_len); | |
296 | } | |
297 | ||
298 | ||
92ac6376 XC |
299 | static int auth_for_each_sta(void *ctx, int (*cb)(struct wpa_state_machine *sm, |
300 | void *ctx), | |
301 | void *cb_ctx) | |
302 | { | |
303 | struct ibss_rsn *ibss_rsn = ctx; | |
304 | struct ibss_rsn_peer *peer; | |
305 | ||
306 | wpa_printf(MSG_DEBUG, "AUTH: for_each_sta"); | |
307 | ||
308 | for (peer = ibss_rsn->peers; peer; peer = peer->next) { | |
309 | if (peer->auth && cb(peer->auth, cb_ctx)) | |
310 | return 1; | |
311 | } | |
312 | ||
313 | return 0; | |
314 | } | |
315 | ||
316 | ||
e640888c AQ |
317 | static void ibss_set_sta_authorized(struct ibss_rsn *ibss_rsn, |
318 | struct ibss_rsn_peer *peer, int authorized) | |
319 | { | |
320 | int res; | |
321 | ||
322 | if (authorized) { | |
323 | res = wpa_drv_sta_set_flags(ibss_rsn->wpa_s, peer->addr, | |
324 | WPA_STA_AUTHORIZED, | |
325 | WPA_STA_AUTHORIZED, ~0); | |
326 | wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " authorizing port", | |
327 | MAC2STR(peer->addr)); | |
328 | } else { | |
329 | res = wpa_drv_sta_set_flags(ibss_rsn->wpa_s, peer->addr, | |
330 | 0, 0, ~WPA_STA_AUTHORIZED); | |
331 | wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " unauthorizing port", | |
332 | MAC2STR(peer->addr)); | |
333 | } | |
334 | ||
335 | if (res && errno != ENOENT) { | |
336 | wpa_printf(MSG_DEBUG, "Could not set station " MACSTR " flags " | |
337 | "for kernel driver (errno=%d)", | |
338 | MAC2STR(peer->addr), errno); | |
339 | } | |
340 | } | |
341 | ||
342 | ||
343 | static void auth_set_eapol(void *ctx, const u8 *addr, | |
344 | wpa_eapol_variable var, int value) | |
345 | { | |
346 | struct ibss_rsn *ibss_rsn = ctx; | |
347 | struct ibss_rsn_peer *peer = ibss_rsn_get_peer(ibss_rsn, addr); | |
348 | ||
349 | if (peer == NULL) | |
350 | return; | |
351 | ||
352 | switch (var) { | |
353 | case WPA_EAPOL_authorized: | |
354 | ibss_set_sta_authorized(ibss_rsn, peer, value); | |
355 | break; | |
356 | default: | |
357 | /* do not handle any other event */ | |
358 | wpa_printf(MSG_DEBUG, "AUTH: eapol event not handled %d", var); | |
359 | break; | |
360 | } | |
361 | } | |
362 | ||
363 | ||
11ef8d35 JM |
364 | static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn, |
365 | const u8 *own_addr) | |
366 | { | |
367 | struct wpa_auth_config conf; | |
368 | struct wpa_auth_callbacks cb; | |
369 | ||
370 | wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine"); | |
371 | ||
372 | os_memset(&conf, 0, sizeof(conf)); | |
373 | conf.wpa = 2; | |
374 | conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK; | |
375 | conf.wpa_pairwise = WPA_CIPHER_CCMP; | |
376 | conf.rsn_pairwise = WPA_CIPHER_CCMP; | |
377 | conf.wpa_group = WPA_CIPHER_CCMP; | |
378 | conf.eapol_version = 2; | |
13579b98 | 379 | conf.wpa_group_rekey = 600; |
11ef8d35 JM |
380 | |
381 | os_memset(&cb, 0, sizeof(cb)); | |
382 | cb.ctx = ibss_rsn; | |
383 | cb.logger = auth_logger; | |
e640888c | 384 | cb.set_eapol = auth_set_eapol; |
11ef8d35 JM |
385 | cb.send_eapol = auth_send_eapol; |
386 | cb.get_psk = auth_get_psk; | |
98f14041 | 387 | cb.set_key = auth_set_key; |
92ac6376 | 388 | cb.for_each_sta = auth_for_each_sta; |
11ef8d35 JM |
389 | |
390 | ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb); | |
391 | if (ibss_rsn->auth_group == NULL) { | |
392 | wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed"); | |
393 | return -1; | |
394 | } | |
395 | ||
457a126e JB |
396 | wpa_init_keys(ibss_rsn->auth_group); |
397 | ||
11ef8d35 JM |
398 | return 0; |
399 | } | |
400 | ||
401 | ||
402 | static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn, | |
403 | struct ibss_rsn_peer *peer) | |
404 | { | |
405 | peer->auth = wpa_auth_sta_init(ibss_rsn->auth_group, peer->addr); | |
406 | if (peer->auth == NULL) { | |
407 | wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed"); | |
408 | return -1; | |
409 | } | |
410 | ||
d0fc6e12 JM |
411 | /* TODO: get peer RSN IE with Probe Request */ |
412 | if (wpa_validate_wpa_ie(ibss_rsn->auth_group, peer->auth, | |
4691fc7b | 413 | (u8 *) "\x30\x14\x01\x00" |
d0fc6e12 JM |
414 | "\x00\x0f\xac\x04" |
415 | "\x01\x00\x00\x0f\xac\x04" | |
4691fc7b JM |
416 | "\x01\x00\x00\x0f\xac\x02" |
417 | "\x00\x00", 22, NULL, 0) != | |
d0fc6e12 | 418 | WPA_IE_OK) { |
11ef8d35 JM |
419 | wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed"); |
420 | return -1; | |
421 | } | |
11ef8d35 | 422 | |
6f9b5d16 JM |
423 | if (wpa_auth_sm_event(peer->auth, WPA_ASSOC)) |
424 | return -1; | |
11ef8d35 | 425 | |
6f9b5d16 JM |
426 | if (wpa_auth_sta_associated(ibss_rsn->auth_group, peer->auth)) |
427 | return -1; | |
11ef8d35 JM |
428 | |
429 | return 0; | |
430 | } | |
431 | ||
432 | ||
433 | int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr) | |
434 | { | |
435 | struct ibss_rsn_peer *peer; | |
436 | ||
78177a00 JM |
437 | if (ibss_rsn == NULL) |
438 | return -1; | |
439 | ||
fa7187bf AQ |
440 | if (ibss_rsn_get_peer(ibss_rsn, addr)) { |
441 | wpa_printf(MSG_DEBUG, "RSN: IBSS Authenticator and Supplicant " | |
442 | "for peer " MACSTR " already running", | |
443 | MAC2STR(addr)); | |
444 | return 0; | |
6c9a98a2 JM |
445 | } |
446 | ||
11ef8d35 JM |
447 | wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator and " |
448 | "Supplicant for peer " MACSTR, MAC2STR(addr)); | |
449 | ||
450 | peer = os_zalloc(sizeof(*peer)); | |
451 | if (peer == NULL) | |
452 | return -1; | |
453 | ||
e2d492dd | 454 | peer->ibss_rsn = ibss_rsn; |
11ef8d35 JM |
455 | os_memcpy(peer->addr, addr, ETH_ALEN); |
456 | ||
457 | if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr, ibss_rsn->psk) | |
458 | < 0) { | |
459 | ibss_rsn_free(peer); | |
460 | return -1; | |
461 | } | |
462 | ||
463 | if (ibss_rsn_auth_init(ibss_rsn, peer) < 0) { | |
464 | ibss_rsn_free(peer); | |
465 | return -1; | |
466 | } | |
467 | ||
468 | peer->next = ibss_rsn->peers; | |
469 | ibss_rsn->peers = peer; | |
470 | ||
471 | return 0; | |
472 | } | |
473 | ||
474 | ||
ea244d21 XC |
475 | void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac) |
476 | { | |
477 | struct ibss_rsn_peer *peer, *prev; | |
478 | ||
479 | if (ibss_rsn == NULL) | |
480 | return; | |
481 | ||
482 | if (peermac == NULL) { | |
483 | /* remove all peers */ | |
484 | wpa_printf(MSG_DEBUG, "%s: Remove all peers", __func__); | |
485 | peer = ibss_rsn->peers; | |
486 | while (peer) { | |
487 | prev = peer; | |
488 | peer = peer->next; | |
489 | ibss_rsn_free(prev); | |
490 | ibss_rsn->peers = peer; | |
491 | } | |
492 | } else { | |
493 | /* remove specific peer */ | |
494 | wpa_printf(MSG_DEBUG, "%s: Remove specific peer " MACSTR, | |
495 | __func__, MAC2STR(peermac)); | |
496 | ||
497 | for (prev = NULL, peer = ibss_rsn->peers; peer != NULL; | |
498 | prev = peer, peer = peer->next) { | |
499 | if (os_memcmp(peermac, peer->addr, ETH_ALEN) == 0) { | |
500 | if (prev == NULL) | |
501 | ibss_rsn->peers = peer->next; | |
502 | else | |
503 | prev->next = peer->next; | |
504 | ibss_rsn_free(peer); | |
505 | wpa_printf(MSG_DEBUG, "%s: Successfully " | |
506 | "removed a specific peer", | |
507 | __func__); | |
508 | break; | |
509 | } | |
510 | } | |
511 | } | |
512 | } | |
513 | ||
514 | ||
11ef8d35 JM |
515 | struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s) |
516 | { | |
517 | struct ibss_rsn *ibss_rsn; | |
518 | ||
519 | ibss_rsn = os_zalloc(sizeof(*ibss_rsn)); | |
520 | if (ibss_rsn == NULL) | |
521 | return NULL; | |
522 | ibss_rsn->wpa_s = wpa_s; | |
523 | ||
524 | if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr) < 0) { | |
525 | ibss_rsn_deinit(ibss_rsn); | |
526 | return NULL; | |
527 | } | |
528 | ||
529 | return ibss_rsn; | |
530 | } | |
531 | ||
532 | ||
533 | void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn) | |
534 | { | |
535 | struct ibss_rsn_peer *peer, *prev; | |
536 | ||
537 | if (ibss_rsn == NULL) | |
538 | return; | |
539 | ||
540 | peer = ibss_rsn->peers; | |
541 | while (peer) { | |
542 | prev = peer; | |
543 | peer = peer->next; | |
544 | ibss_rsn_free(prev); | |
545 | } | |
546 | ||
547 | wpa_deinit(ibss_rsn->auth_group); | |
548 | os_free(ibss_rsn); | |
549 | ||
550 | } | |
8be18440 JM |
551 | |
552 | ||
553 | static int ibss_rsn_eapol_dst_supp(const u8 *buf, size_t len) | |
554 | { | |
555 | const struct ieee802_1x_hdr *hdr; | |
556 | const struct wpa_eapol_key *key; | |
557 | u16 key_info; | |
558 | size_t plen; | |
559 | ||
560 | /* TODO: Support other EAPOL packets than just EAPOL-Key */ | |
561 | ||
562 | if (len < sizeof(*hdr) + sizeof(*key)) | |
563 | return -1; | |
564 | ||
565 | hdr = (const struct ieee802_1x_hdr *) buf; | |
566 | key = (const struct wpa_eapol_key *) (hdr + 1); | |
567 | plen = be_to_host16(hdr->length); | |
568 | ||
569 | if (hdr->version < EAPOL_VERSION) { | |
570 | /* TODO: backwards compatibility */ | |
571 | } | |
572 | if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) { | |
573 | wpa_printf(MSG_DEBUG, "RSN: EAPOL frame (type %u) discarded, " | |
574 | "not a Key frame", hdr->type); | |
575 | return -1; | |
576 | } | |
577 | if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) { | |
578 | wpa_printf(MSG_DEBUG, "RSN: EAPOL frame payload size %lu " | |
579 | "invalid (frame size %lu)", | |
580 | (unsigned long) plen, (unsigned long) len); | |
581 | return -1; | |
582 | } | |
583 | ||
584 | if (key->type != EAPOL_KEY_TYPE_RSN) { | |
585 | wpa_printf(MSG_DEBUG, "RSN: EAPOL-Key type (%d) unknown, " | |
586 | "discarded", key->type); | |
587 | return -1; | |
588 | } | |
589 | ||
590 | key_info = WPA_GET_BE16(key->key_info); | |
591 | ||
592 | return !!(key_info & WPA_KEY_INFO_ACK); | |
593 | } | |
594 | ||
595 | ||
596 | static int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn, | |
597 | struct ibss_rsn_peer *peer, | |
598 | const u8 *buf, size_t len) | |
599 | { | |
600 | int supp; | |
601 | u8 *tmp; | |
602 | ||
603 | supp = ibss_rsn_eapol_dst_supp(buf, len); | |
604 | if (supp < 0) | |
605 | return -1; | |
606 | ||
607 | tmp = os_malloc(len); | |
608 | if (tmp == NULL) | |
609 | return -1; | |
610 | os_memcpy(tmp, buf, len); | |
611 | if (supp) { | |
612 | wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant"); | |
613 | wpa_sm_rx_eapol(peer->supp, peer->addr, tmp, len); | |
614 | } else { | |
615 | wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Authenticator"); | |
616 | wpa_receive(ibss_rsn->auth_group, peer->auth, tmp, len); | |
617 | } | |
618 | os_free(tmp); | |
619 | ||
620 | return 1; | |
621 | } | |
622 | ||
623 | ||
624 | int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr, | |
625 | const u8 *buf, size_t len) | |
626 | { | |
627 | struct ibss_rsn_peer *peer; | |
628 | ||
78177a00 JM |
629 | if (ibss_rsn == NULL) |
630 | return -1; | |
631 | ||
fa7187bf AQ |
632 | peer = ibss_rsn_get_peer(ibss_rsn, src_addr); |
633 | if (peer) | |
634 | return ibss_rsn_process_rx_eapol(ibss_rsn, peer, buf, len); | |
8be18440 JM |
635 | |
636 | if (ibss_rsn_eapol_dst_supp(buf, len) > 0) { | |
637 | /* | |
638 | * Create new IBSS peer based on an EAPOL message from the peer | |
639 | * Authenticator. | |
640 | */ | |
641 | if (ibss_rsn_start(ibss_rsn, src_addr) < 0) | |
642 | return -1; | |
643 | return ibss_rsn_process_rx_eapol(ibss_rsn, ibss_rsn->peers, | |
644 | buf, len); | |
645 | } | |
646 | ||
647 | return 0; | |
648 | } | |
b9a2e577 JM |
649 | |
650 | ||
651 | void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk) | |
652 | { | |
78177a00 JM |
653 | if (ibss_rsn == NULL) |
654 | return; | |
b9a2e577 JM |
655 | os_memcpy(ibss_rsn->psk, psk, PMK_LEN); |
656 | } |