]>
Commit | Line | Data |
---|---|---|
11ef8d35 JM |
1 | /* |
2 | * wpa_supplicant - IBSS RSN | |
3 | * Copyright (c) 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 "common.h" | |
e2d492dd | 18 | #include "l2_packet/l2_packet.h" |
3acb5005 JM |
19 | #include "rsn_supp/wpa.h" |
20 | #include "rsn_supp/wpa_ie.h" | |
71934751 | 21 | #include "ap/wpa_auth.h" |
1057d78e | 22 | #include "wpa_supplicant_i.h" |
ea038e0d | 23 | #include "driver_i.h" |
11ef8d35 JM |
24 | #include "ibss_rsn.h" |
25 | ||
26 | ||
27 | static void ibss_rsn_free(struct ibss_rsn_peer *peer) | |
28 | { | |
29 | wpa_auth_sta_deinit(peer->auth); | |
30 | wpa_sm_deinit(peer->supp); | |
31 | os_free(peer); | |
32 | } | |
33 | ||
34 | ||
71934751 | 35 | static void supp_set_state(void *ctx, enum wpa_states state) |
3146b2b9 JM |
36 | { |
37 | struct ibss_rsn_peer *peer = ctx; | |
38 | peer->supp_state = state; | |
39 | } | |
40 | ||
41 | ||
11ef8d35 JM |
42 | static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf, |
43 | size_t len) | |
44 | { | |
e2d492dd JM |
45 | struct ibss_rsn_peer *peer = ctx; |
46 | struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s; | |
11ef8d35 JM |
47 | |
48 | wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x " | |
49 | "len=%lu)", | |
50 | __func__, MAC2STR(dest), proto, (unsigned long) len); | |
51 | ||
e2d492dd JM |
52 | if (wpa_s->l2) |
53 | return l2_packet_send(wpa_s->l2, dest, proto, buf, len); | |
11ef8d35 | 54 | |
e2d492dd | 55 | return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len); |
11ef8d35 JM |
56 | } |
57 | ||
58 | ||
59 | static u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data, | |
60 | u16 data_len, size_t *msg_len, void **data_pos) | |
61 | { | |
62 | struct ieee802_1x_hdr *hdr; | |
63 | ||
64 | wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)", | |
65 | __func__, type, data_len); | |
66 | ||
67 | *msg_len = sizeof(*hdr) + data_len; | |
68 | hdr = os_malloc(*msg_len); | |
69 | if (hdr == NULL) | |
70 | return NULL; | |
71 | ||
72 | hdr->version = 2; | |
73 | hdr->type = type; | |
74 | hdr->length = host_to_be16(data_len); | |
75 | ||
76 | if (data) | |
77 | os_memcpy(hdr + 1, data, data_len); | |
78 | else | |
79 | os_memset(hdr + 1, 0, data_len); | |
80 | ||
81 | if (data_pos) | |
82 | *data_pos = hdr + 1; | |
83 | ||
84 | return (u8 *) hdr; | |
85 | } | |
86 | ||
87 | ||
88 | static int supp_get_beacon_ie(void *ctx) | |
89 | { | |
4691fc7b JM |
90 | struct ibss_rsn_peer *peer = ctx; |
91 | ||
11ef8d35 | 92 | wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); |
4691fc7b JM |
93 | /* TODO: get correct RSN IE */ |
94 | return wpa_sm_set_ap_rsn_ie(peer->supp, | |
95 | (u8 *) "\x30\x14\x01\x00" | |
96 | "\x00\x0f\xac\x04" | |
97 | "\x01\x00\x00\x0f\xac\x04" | |
98 | "\x01\x00\x00\x0f\xac\x02" | |
99 | "\x00\x00", 22); | |
11ef8d35 JM |
100 | } |
101 | ||
102 | ||
71934751 | 103 | static int supp_set_key(void *ctx, enum wpa_alg alg, |
11ef8d35 JM |
104 | const u8 *addr, int key_idx, int set_tx, |
105 | const u8 *seq, size_t seq_len, | |
106 | const u8 *key, size_t key_len) | |
107 | { | |
98f14041 JM |
108 | struct ibss_rsn_peer *peer = ctx; |
109 | ||
a486c0c7 JM |
110 | wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d " |
111 | "set_tx=%d)", | |
112 | __func__, alg, MAC2STR(addr), key_idx, set_tx); | |
113 | wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len); | |
114 | wpa_hexdump_key(MSG_DEBUG, "SUPP: set_key - key", key, key_len); | |
115 | ||
98f14041 JM |
116 | if (key_idx == 0) { |
117 | /* | |
118 | * In IBSS RSN, the pairwise key from the 4-way handshake | |
119 | * initiated by the peer with highest MAC address is used. | |
120 | */ | |
121 | if (os_memcmp(peer->ibss_rsn->wpa_s->own_addr, peer->addr, | |
a486c0c7 JM |
122 | ETH_ALEN) > 0) { |
123 | wpa_printf(MSG_DEBUG, "SUPP: Do not use this PTK"); | |
98f14041 | 124 | return 0; |
a486c0c7 | 125 | } |
98f14041 JM |
126 | } |
127 | ||
98f14041 JM |
128 | return wpa_drv_set_key(peer->ibss_rsn->wpa_s, alg, addr, key_idx, |
129 | set_tx, seq, seq_len, key, key_len); | |
11ef8d35 JM |
130 | } |
131 | ||
132 | ||
3146b2b9 JM |
133 | static void * supp_get_network_ctx(void *ctx) |
134 | { | |
135 | struct ibss_rsn_peer *peer = ctx; | |
136 | return wpa_supplicant_get_ssid(peer->ibss_rsn->wpa_s); | |
137 | } | |
138 | ||
139 | ||
11ef8d35 JM |
140 | static int supp_mlme_setprotection(void *ctx, const u8 *addr, |
141 | int protection_type, int key_type) | |
142 | { | |
143 | wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d " | |
144 | "key_type=%d)", | |
145 | __func__, MAC2STR(addr), protection_type, key_type); | |
146 | return 0; | |
147 | } | |
148 | ||
149 | ||
150 | static void supp_cancel_auth_timeout(void *ctx) | |
151 | { | |
152 | wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); | |
153 | } | |
154 | ||
155 | ||
156 | int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr, | |
157 | const u8 *psk) | |
158 | { | |
159 | struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx)); | |
160 | if (ctx == NULL) | |
161 | return -1; | |
162 | ||
163 | ctx->ctx = peer; | |
0f057fb2 | 164 | ctx->msg_ctx = peer->ibss_rsn->wpa_s; |
3146b2b9 | 165 | ctx->set_state = supp_set_state; |
11ef8d35 JM |
166 | ctx->ether_send = supp_ether_send; |
167 | ctx->get_beacon_ie = supp_get_beacon_ie; | |
168 | ctx->alloc_eapol = supp_alloc_eapol; | |
169 | ctx->set_key = supp_set_key; | |
3146b2b9 | 170 | ctx->get_network_ctx = supp_get_network_ctx; |
11ef8d35 JM |
171 | ctx->mlme_setprotection = supp_mlme_setprotection; |
172 | ctx->cancel_auth_timeout = supp_cancel_auth_timeout; | |
173 | peer->supp = wpa_sm_init(ctx); | |
174 | if (peer->supp == NULL) { | |
175 | wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed"); | |
176 | return -1; | |
177 | } | |
178 | ||
179 | wpa_sm_set_own_addr(peer->supp, own_addr); | |
180 | wpa_sm_set_param(peer->supp, WPA_PARAM_RSN_ENABLED, 1); | |
181 | wpa_sm_set_param(peer->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN); | |
182 | wpa_sm_set_param(peer->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP); | |
183 | wpa_sm_set_param(peer->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP); | |
184 | wpa_sm_set_param(peer->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK); | |
185 | wpa_sm_set_pmk(peer->supp, psk, PMK_LEN); | |
186 | ||
11ef8d35 JM |
187 | peer->supp_ie_len = sizeof(peer->supp_ie); |
188 | if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie, | |
189 | &peer->supp_ie_len) < 0) { | |
190 | wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()" | |
191 | " failed"); | |
192 | return -1; | |
193 | } | |
11ef8d35 JM |
194 | |
195 | wpa_sm_notify_assoc(peer->supp, peer->addr); | |
196 | ||
197 | return 0; | |
198 | } | |
199 | ||
200 | ||
201 | static void auth_logger(void *ctx, const u8 *addr, logger_level level, | |
202 | const char *txt) | |
203 | { | |
204 | if (addr) | |
205 | wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s", | |
206 | MAC2STR(addr), txt); | |
207 | else | |
208 | wpa_printf(MSG_DEBUG, "AUTH: %s", txt); | |
209 | } | |
210 | ||
211 | ||
212 | static const u8 * auth_get_psk(void *ctx, const u8 *addr, const u8 *prev_psk) | |
213 | { | |
214 | struct ibss_rsn *ibss_rsn = ctx; | |
215 | wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)", | |
216 | __func__, MAC2STR(addr), prev_psk); | |
217 | if (prev_psk) | |
218 | return NULL; | |
219 | return ibss_rsn->psk; | |
220 | } | |
221 | ||
222 | ||
223 | static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data, | |
224 | size_t data_len, int encrypt) | |
225 | { | |
da3c6a5e JM |
226 | struct ibss_rsn *ibss_rsn = ctx; |
227 | struct wpa_supplicant *wpa_s = ibss_rsn->wpa_s; | |
11ef8d35 JM |
228 | |
229 | wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu " | |
230 | "encrypt=%d)", | |
231 | __func__, MAC2STR(addr), (unsigned long) data_len, encrypt); | |
232 | ||
e2d492dd JM |
233 | if (wpa_s->l2) |
234 | return l2_packet_send(wpa_s->l2, addr, ETH_P_EAPOL, data, | |
235 | data_len); | |
11ef8d35 | 236 | |
e2d492dd | 237 | return wpa_drv_send_eapol(wpa_s, addr, ETH_P_EAPOL, data, data_len); |
11ef8d35 JM |
238 | } |
239 | ||
240 | ||
71934751 JM |
241 | static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, |
242 | const u8 *addr, int idx, u8 *key, size_t key_len) | |
98f14041 JM |
243 | { |
244 | struct ibss_rsn *ibss_rsn = ctx; | |
245 | u8 seq[6]; | |
98f14041 JM |
246 | |
247 | os_memset(seq, 0, sizeof(seq)); | |
a486c0c7 JM |
248 | |
249 | if (addr) { | |
250 | wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d addr=" MACSTR | |
251 | " key_idx=%d)", | |
252 | __func__, alg, MAC2STR(addr), idx); | |
253 | } else { | |
254 | wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d key_idx=%d)", | |
255 | __func__, alg, idx); | |
256 | } | |
257 | wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len); | |
258 | ||
98f14041 JM |
259 | if (idx == 0) { |
260 | /* | |
261 | * In IBSS RSN, the pairwise key from the 4-way handshake | |
262 | * initiated by the peer with highest MAC address is used. | |
263 | */ | |
a416fb47 JM |
264 | if (addr == NULL || |
265 | os_memcmp(ibss_rsn->wpa_s->own_addr, addr, ETH_ALEN) < 0) { | |
a486c0c7 | 266 | wpa_printf(MSG_DEBUG, "AUTH: Do not use this PTK"); |
98f14041 | 267 | return 0; |
a486c0c7 | 268 | } |
98f14041 JM |
269 | } |
270 | ||
271 | return wpa_drv_set_key(ibss_rsn->wpa_s, alg, addr, idx, | |
272 | 1, seq, 6, key, key_len); | |
273 | } | |
274 | ||
275 | ||
11ef8d35 JM |
276 | static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn, |
277 | const u8 *own_addr) | |
278 | { | |
279 | struct wpa_auth_config conf; | |
280 | struct wpa_auth_callbacks cb; | |
281 | ||
282 | wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine"); | |
283 | ||
284 | os_memset(&conf, 0, sizeof(conf)); | |
285 | conf.wpa = 2; | |
286 | conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK; | |
287 | conf.wpa_pairwise = WPA_CIPHER_CCMP; | |
288 | conf.rsn_pairwise = WPA_CIPHER_CCMP; | |
289 | conf.wpa_group = WPA_CIPHER_CCMP; | |
290 | conf.eapol_version = 2; | |
291 | ||
292 | os_memset(&cb, 0, sizeof(cb)); | |
293 | cb.ctx = ibss_rsn; | |
294 | cb.logger = auth_logger; | |
295 | cb.send_eapol = auth_send_eapol; | |
296 | cb.get_psk = auth_get_psk; | |
98f14041 | 297 | cb.set_key = auth_set_key; |
11ef8d35 JM |
298 | |
299 | ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb); | |
300 | if (ibss_rsn->auth_group == NULL) { | |
301 | wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed"); | |
302 | return -1; | |
303 | } | |
304 | ||
305 | return 0; | |
306 | } | |
307 | ||
308 | ||
309 | static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn, | |
310 | struct ibss_rsn_peer *peer) | |
311 | { | |
312 | peer->auth = wpa_auth_sta_init(ibss_rsn->auth_group, peer->addr); | |
313 | if (peer->auth == NULL) { | |
314 | wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed"); | |
315 | return -1; | |
316 | } | |
317 | ||
d0fc6e12 JM |
318 | /* TODO: get peer RSN IE with Probe Request */ |
319 | if (wpa_validate_wpa_ie(ibss_rsn->auth_group, peer->auth, | |
4691fc7b | 320 | (u8 *) "\x30\x14\x01\x00" |
d0fc6e12 JM |
321 | "\x00\x0f\xac\x04" |
322 | "\x01\x00\x00\x0f\xac\x04" | |
4691fc7b JM |
323 | "\x01\x00\x00\x0f\xac\x02" |
324 | "\x00\x00", 22, NULL, 0) != | |
d0fc6e12 | 325 | WPA_IE_OK) { |
11ef8d35 JM |
326 | wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed"); |
327 | return -1; | |
328 | } | |
11ef8d35 | 329 | |
6f9b5d16 JM |
330 | if (wpa_auth_sm_event(peer->auth, WPA_ASSOC)) |
331 | return -1; | |
11ef8d35 | 332 | |
6f9b5d16 JM |
333 | if (wpa_auth_sta_associated(ibss_rsn->auth_group, peer->auth)) |
334 | return -1; | |
11ef8d35 JM |
335 | |
336 | return 0; | |
337 | } | |
338 | ||
339 | ||
340 | int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr) | |
341 | { | |
342 | struct ibss_rsn_peer *peer; | |
343 | ||
344 | wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator and " | |
345 | "Supplicant for peer " MACSTR, MAC2STR(addr)); | |
346 | ||
347 | peer = os_zalloc(sizeof(*peer)); | |
348 | if (peer == NULL) | |
349 | return -1; | |
350 | ||
e2d492dd | 351 | peer->ibss_rsn = ibss_rsn; |
11ef8d35 JM |
352 | os_memcpy(peer->addr, addr, ETH_ALEN); |
353 | ||
354 | if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr, ibss_rsn->psk) | |
355 | < 0) { | |
356 | ibss_rsn_free(peer); | |
357 | return -1; | |
358 | } | |
359 | ||
360 | if (ibss_rsn_auth_init(ibss_rsn, peer) < 0) { | |
361 | ibss_rsn_free(peer); | |
362 | return -1; | |
363 | } | |
364 | ||
365 | peer->next = ibss_rsn->peers; | |
366 | ibss_rsn->peers = peer; | |
367 | ||
368 | return 0; | |
369 | } | |
370 | ||
371 | ||
372 | struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s) | |
373 | { | |
374 | struct ibss_rsn *ibss_rsn; | |
375 | ||
376 | ibss_rsn = os_zalloc(sizeof(*ibss_rsn)); | |
377 | if (ibss_rsn == NULL) | |
378 | return NULL; | |
379 | ibss_rsn->wpa_s = wpa_s; | |
380 | ||
381 | if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr) < 0) { | |
382 | ibss_rsn_deinit(ibss_rsn); | |
383 | return NULL; | |
384 | } | |
385 | ||
386 | return ibss_rsn; | |
387 | } | |
388 | ||
389 | ||
390 | void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn) | |
391 | { | |
392 | struct ibss_rsn_peer *peer, *prev; | |
393 | ||
394 | if (ibss_rsn == NULL) | |
395 | return; | |
396 | ||
397 | peer = ibss_rsn->peers; | |
398 | while (peer) { | |
399 | prev = peer; | |
400 | peer = peer->next; | |
401 | ibss_rsn_free(prev); | |
402 | } | |
403 | ||
404 | wpa_deinit(ibss_rsn->auth_group); | |
405 | os_free(ibss_rsn); | |
406 | ||
407 | } | |
8be18440 JM |
408 | |
409 | ||
410 | static int ibss_rsn_eapol_dst_supp(const u8 *buf, size_t len) | |
411 | { | |
412 | const struct ieee802_1x_hdr *hdr; | |
413 | const struct wpa_eapol_key *key; | |
414 | u16 key_info; | |
415 | size_t plen; | |
416 | ||
417 | /* TODO: Support other EAPOL packets than just EAPOL-Key */ | |
418 | ||
419 | if (len < sizeof(*hdr) + sizeof(*key)) | |
420 | return -1; | |
421 | ||
422 | hdr = (const struct ieee802_1x_hdr *) buf; | |
423 | key = (const struct wpa_eapol_key *) (hdr + 1); | |
424 | plen = be_to_host16(hdr->length); | |
425 | ||
426 | if (hdr->version < EAPOL_VERSION) { | |
427 | /* TODO: backwards compatibility */ | |
428 | } | |
429 | if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) { | |
430 | wpa_printf(MSG_DEBUG, "RSN: EAPOL frame (type %u) discarded, " | |
431 | "not a Key frame", hdr->type); | |
432 | return -1; | |
433 | } | |
434 | if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) { | |
435 | wpa_printf(MSG_DEBUG, "RSN: EAPOL frame payload size %lu " | |
436 | "invalid (frame size %lu)", | |
437 | (unsigned long) plen, (unsigned long) len); | |
438 | return -1; | |
439 | } | |
440 | ||
441 | if (key->type != EAPOL_KEY_TYPE_RSN) { | |
442 | wpa_printf(MSG_DEBUG, "RSN: EAPOL-Key type (%d) unknown, " | |
443 | "discarded", key->type); | |
444 | return -1; | |
445 | } | |
446 | ||
447 | key_info = WPA_GET_BE16(key->key_info); | |
448 | ||
449 | return !!(key_info & WPA_KEY_INFO_ACK); | |
450 | } | |
451 | ||
452 | ||
453 | static int ibss_rsn_process_rx_eapol(struct ibss_rsn *ibss_rsn, | |
454 | struct ibss_rsn_peer *peer, | |
455 | const u8 *buf, size_t len) | |
456 | { | |
457 | int supp; | |
458 | u8 *tmp; | |
459 | ||
460 | supp = ibss_rsn_eapol_dst_supp(buf, len); | |
461 | if (supp < 0) | |
462 | return -1; | |
463 | ||
464 | tmp = os_malloc(len); | |
465 | if (tmp == NULL) | |
466 | return -1; | |
467 | os_memcpy(tmp, buf, len); | |
468 | if (supp) { | |
469 | wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Supplicant"); | |
470 | wpa_sm_rx_eapol(peer->supp, peer->addr, tmp, len); | |
471 | } else { | |
472 | wpa_printf(MSG_DEBUG, "RSN: IBSS RX EAPOL for Authenticator"); | |
473 | wpa_receive(ibss_rsn->auth_group, peer->auth, tmp, len); | |
474 | } | |
475 | os_free(tmp); | |
476 | ||
477 | return 1; | |
478 | } | |
479 | ||
480 | ||
481 | int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr, | |
482 | const u8 *buf, size_t len) | |
483 | { | |
484 | struct ibss_rsn_peer *peer; | |
485 | ||
486 | for (peer = ibss_rsn->peers; peer; peer = peer->next) { | |
487 | if (os_memcmp(src_addr, peer->addr, ETH_ALEN) == 0) | |
488 | return ibss_rsn_process_rx_eapol(ibss_rsn, peer, | |
489 | buf, len); | |
490 | } | |
491 | ||
492 | if (ibss_rsn_eapol_dst_supp(buf, len) > 0) { | |
493 | /* | |
494 | * Create new IBSS peer based on an EAPOL message from the peer | |
495 | * Authenticator. | |
496 | */ | |
497 | if (ibss_rsn_start(ibss_rsn, src_addr) < 0) | |
498 | return -1; | |
499 | return ibss_rsn_process_rx_eapol(ibss_rsn, ibss_rsn->peers, | |
500 | buf, len); | |
501 | } | |
502 | ||
503 | return 0; | |
504 | } | |
b9a2e577 JM |
505 | |
506 | ||
507 | void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk) | |
508 | { | |
509 | os_memcpy(ibss_rsn->psk, psk, PMK_LEN); | |
510 | } |