]>
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" |
11ef8d35 JM |
19 | #include "wpa_supplicant_i.h" |
20 | #include "wpa.h" | |
21 | #include "wpa_ie.h" | |
22 | #include "../hostapd/wpa.h" | |
23 | #include "ibss_rsn.h" | |
24 | ||
25 | ||
26 | static void ibss_rsn_free(struct ibss_rsn_peer *peer) | |
27 | { | |
28 | wpa_auth_sta_deinit(peer->auth); | |
29 | wpa_sm_deinit(peer->supp); | |
30 | os_free(peer); | |
31 | } | |
32 | ||
33 | ||
34 | static int supp_ether_send(void *ctx, const u8 *dest, u16 proto, const u8 *buf, | |
35 | size_t len) | |
36 | { | |
e2d492dd JM |
37 | struct ibss_rsn_peer *peer = ctx; |
38 | struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s; | |
11ef8d35 JM |
39 | |
40 | wpa_printf(MSG_DEBUG, "SUPP: %s(dest=" MACSTR " proto=0x%04x " | |
41 | "len=%lu)", | |
42 | __func__, MAC2STR(dest), proto, (unsigned long) len); | |
43 | ||
e2d492dd JM |
44 | if (wpa_s->l2) |
45 | return l2_packet_send(wpa_s->l2, dest, proto, buf, len); | |
11ef8d35 | 46 | |
e2d492dd | 47 | return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len); |
11ef8d35 JM |
48 | } |
49 | ||
50 | ||
51 | static u8 * supp_alloc_eapol(void *ctx, u8 type, const void *data, | |
52 | u16 data_len, size_t *msg_len, void **data_pos) | |
53 | { | |
54 | struct ieee802_1x_hdr *hdr; | |
55 | ||
56 | wpa_printf(MSG_DEBUG, "SUPP: %s(type=%d data_len=%d)", | |
57 | __func__, type, data_len); | |
58 | ||
59 | *msg_len = sizeof(*hdr) + data_len; | |
60 | hdr = os_malloc(*msg_len); | |
61 | if (hdr == NULL) | |
62 | return NULL; | |
63 | ||
64 | hdr->version = 2; | |
65 | hdr->type = type; | |
66 | hdr->length = host_to_be16(data_len); | |
67 | ||
68 | if (data) | |
69 | os_memcpy(hdr + 1, data, data_len); | |
70 | else | |
71 | os_memset(hdr + 1, 0, data_len); | |
72 | ||
73 | if (data_pos) | |
74 | *data_pos = hdr + 1; | |
75 | ||
76 | return (u8 *) hdr; | |
77 | } | |
78 | ||
79 | ||
80 | static int supp_get_beacon_ie(void *ctx) | |
81 | { | |
82 | wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); | |
83 | /* TODO */ | |
84 | return -1; | |
85 | } | |
86 | ||
87 | ||
88 | static int supp_set_key(void *ctx, wpa_alg alg, | |
89 | const u8 *addr, int key_idx, int set_tx, | |
90 | const u8 *seq, size_t seq_len, | |
91 | const u8 *key, size_t key_len) | |
92 | { | |
93 | wpa_printf(MSG_DEBUG, "SUPP: %s(alg=%d addr=" MACSTR " key_idx=%d " | |
94 | "set_tx=%d)", | |
95 | __func__, alg, MAC2STR(addr), key_idx, set_tx); | |
96 | wpa_hexdump(MSG_DEBUG, "SUPP: set_key - seq", seq, seq_len); | |
97 | wpa_hexdump(MSG_DEBUG, "SUPP: set_key - key", key, key_len); | |
98 | return 0; | |
99 | } | |
100 | ||
101 | ||
102 | static int supp_mlme_setprotection(void *ctx, const u8 *addr, | |
103 | int protection_type, int key_type) | |
104 | { | |
105 | wpa_printf(MSG_DEBUG, "SUPP: %s(addr=" MACSTR " protection_type=%d " | |
106 | "key_type=%d)", | |
107 | __func__, MAC2STR(addr), protection_type, key_type); | |
108 | return 0; | |
109 | } | |
110 | ||
111 | ||
112 | static void supp_cancel_auth_timeout(void *ctx) | |
113 | { | |
114 | wpa_printf(MSG_DEBUG, "SUPP: %s", __func__); | |
115 | } | |
116 | ||
117 | ||
118 | int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr, | |
119 | const u8 *psk) | |
120 | { | |
121 | struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx)); | |
122 | if (ctx == NULL) | |
123 | return -1; | |
124 | ||
125 | ctx->ctx = peer; | |
126 | ctx->ether_send = supp_ether_send; | |
127 | ctx->get_beacon_ie = supp_get_beacon_ie; | |
128 | ctx->alloc_eapol = supp_alloc_eapol; | |
129 | ctx->set_key = supp_set_key; | |
130 | ctx->mlme_setprotection = supp_mlme_setprotection; | |
131 | ctx->cancel_auth_timeout = supp_cancel_auth_timeout; | |
132 | peer->supp = wpa_sm_init(ctx); | |
133 | if (peer->supp == NULL) { | |
134 | wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_init() failed"); | |
135 | return -1; | |
136 | } | |
137 | ||
138 | wpa_sm_set_own_addr(peer->supp, own_addr); | |
139 | wpa_sm_set_param(peer->supp, WPA_PARAM_RSN_ENABLED, 1); | |
140 | wpa_sm_set_param(peer->supp, WPA_PARAM_PROTO, WPA_PROTO_RSN); | |
141 | wpa_sm_set_param(peer->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP); | |
142 | wpa_sm_set_param(peer->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP); | |
143 | wpa_sm_set_param(peer->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK); | |
144 | wpa_sm_set_pmk(peer->supp, psk, PMK_LEN); | |
145 | ||
146 | #if 0 /* TODO? */ | |
147 | peer->supp_ie_len = sizeof(peer->supp_ie); | |
148 | if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie, | |
149 | &peer->supp_ie_len) < 0) { | |
150 | wpa_printf(MSG_DEBUG, "SUPP: wpa_sm_set_assoc_wpa_ie_default()" | |
151 | " failed"); | |
152 | return -1; | |
153 | } | |
154 | #endif | |
155 | ||
156 | wpa_sm_notify_assoc(peer->supp, peer->addr); | |
157 | ||
158 | return 0; | |
159 | } | |
160 | ||
161 | ||
162 | static void auth_logger(void *ctx, const u8 *addr, logger_level level, | |
163 | const char *txt) | |
164 | { | |
165 | if (addr) | |
166 | wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s", | |
167 | MAC2STR(addr), txt); | |
168 | else | |
169 | wpa_printf(MSG_DEBUG, "AUTH: %s", txt); | |
170 | } | |
171 | ||
172 | ||
173 | static const u8 * auth_get_psk(void *ctx, const u8 *addr, const u8 *prev_psk) | |
174 | { | |
175 | struct ibss_rsn *ibss_rsn = ctx; | |
176 | wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)", | |
177 | __func__, MAC2STR(addr), prev_psk); | |
178 | if (prev_psk) | |
179 | return NULL; | |
180 | return ibss_rsn->psk; | |
181 | } | |
182 | ||
183 | ||
184 | static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data, | |
185 | size_t data_len, int encrypt) | |
186 | { | |
e2d492dd JM |
187 | struct ibss_rsn_peer *peer = ctx; |
188 | struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s; | |
11ef8d35 JM |
189 | |
190 | wpa_printf(MSG_DEBUG, "AUTH: %s(addr=" MACSTR " data_len=%lu " | |
191 | "encrypt=%d)", | |
192 | __func__, MAC2STR(addr), (unsigned long) data_len, encrypt); | |
193 | ||
e2d492dd JM |
194 | if (wpa_s->l2) |
195 | return l2_packet_send(wpa_s->l2, addr, ETH_P_EAPOL, data, | |
196 | data_len); | |
11ef8d35 | 197 | |
e2d492dd | 198 | return wpa_drv_send_eapol(wpa_s, addr, ETH_P_EAPOL, data, data_len); |
11ef8d35 JM |
199 | } |
200 | ||
201 | ||
202 | static int ibss_rsn_auth_init_group(struct ibss_rsn *ibss_rsn, | |
203 | const u8 *own_addr) | |
204 | { | |
205 | struct wpa_auth_config conf; | |
206 | struct wpa_auth_callbacks cb; | |
207 | ||
208 | wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine"); | |
209 | ||
210 | os_memset(&conf, 0, sizeof(conf)); | |
211 | conf.wpa = 2; | |
212 | conf.wpa_key_mgmt = WPA_KEY_MGMT_PSK; | |
213 | conf.wpa_pairwise = WPA_CIPHER_CCMP; | |
214 | conf.rsn_pairwise = WPA_CIPHER_CCMP; | |
215 | conf.wpa_group = WPA_CIPHER_CCMP; | |
216 | conf.eapol_version = 2; | |
217 | ||
218 | os_memset(&cb, 0, sizeof(cb)); | |
219 | cb.ctx = ibss_rsn; | |
220 | cb.logger = auth_logger; | |
221 | cb.send_eapol = auth_send_eapol; | |
222 | cb.get_psk = auth_get_psk; | |
223 | ||
224 | ibss_rsn->auth_group = wpa_init(own_addr, &conf, &cb); | |
225 | if (ibss_rsn->auth_group == NULL) { | |
226 | wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed"); | |
227 | return -1; | |
228 | } | |
229 | ||
230 | return 0; | |
231 | } | |
232 | ||
233 | ||
234 | static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn, | |
235 | struct ibss_rsn_peer *peer) | |
236 | { | |
237 | peer->auth = wpa_auth_sta_init(ibss_rsn->auth_group, peer->addr); | |
238 | if (peer->auth == NULL) { | |
239 | wpa_printf(MSG_DEBUG, "AUTH: wpa_auth_sta_init() failed"); | |
240 | return -1; | |
241 | } | |
242 | ||
d0fc6e12 JM |
243 | /* TODO: get peer RSN IE with Probe Request */ |
244 | if (wpa_validate_wpa_ie(ibss_rsn->auth_group, peer->auth, | |
245 | (u8 *) "\x30\x12\x01\x00" | |
246 | "\x00\x0f\xac\x04" | |
247 | "\x01\x00\x00\x0f\xac\x04" | |
248 | "\x01\x00\x00\x0f\xac\x02", 20, NULL, 0) != | |
249 | WPA_IE_OK) { | |
11ef8d35 JM |
250 | wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed"); |
251 | return -1; | |
252 | } | |
11ef8d35 JM |
253 | |
254 | wpa_auth_sm_event(peer->auth, WPA_ASSOC); | |
255 | ||
256 | wpa_auth_sta_associated(ibss_rsn->auth_group, peer->auth); | |
257 | ||
258 | return 0; | |
259 | } | |
260 | ||
261 | ||
262 | int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr) | |
263 | { | |
264 | struct ibss_rsn_peer *peer; | |
265 | ||
266 | wpa_printf(MSG_DEBUG, "RSN: Starting IBSS Authenticator and " | |
267 | "Supplicant for peer " MACSTR, MAC2STR(addr)); | |
268 | ||
269 | peer = os_zalloc(sizeof(*peer)); | |
270 | if (peer == NULL) | |
271 | return -1; | |
272 | ||
e2d492dd | 273 | peer->ibss_rsn = ibss_rsn; |
11ef8d35 JM |
274 | os_memcpy(peer->addr, addr, ETH_ALEN); |
275 | ||
276 | if (ibss_rsn_supp_init(peer, ibss_rsn->wpa_s->own_addr, ibss_rsn->psk) | |
277 | < 0) { | |
278 | ibss_rsn_free(peer); | |
279 | return -1; | |
280 | } | |
281 | ||
282 | if (ibss_rsn_auth_init(ibss_rsn, peer) < 0) { | |
283 | ibss_rsn_free(peer); | |
284 | return -1; | |
285 | } | |
286 | ||
287 | peer->next = ibss_rsn->peers; | |
288 | ibss_rsn->peers = peer; | |
289 | ||
290 | return 0; | |
291 | } | |
292 | ||
293 | ||
294 | struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s) | |
295 | { | |
296 | struct ibss_rsn *ibss_rsn; | |
297 | ||
298 | ibss_rsn = os_zalloc(sizeof(*ibss_rsn)); | |
299 | if (ibss_rsn == NULL) | |
300 | return NULL; | |
301 | ibss_rsn->wpa_s = wpa_s; | |
302 | ||
303 | if (ibss_rsn_auth_init_group(ibss_rsn, wpa_s->own_addr) < 0) { | |
304 | ibss_rsn_deinit(ibss_rsn); | |
305 | return NULL; | |
306 | } | |
307 | ||
308 | return ibss_rsn; | |
309 | } | |
310 | ||
311 | ||
312 | void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn) | |
313 | { | |
314 | struct ibss_rsn_peer *peer, *prev; | |
315 | ||
316 | if (ibss_rsn == NULL) | |
317 | return; | |
318 | ||
319 | peer = ibss_rsn->peers; | |
320 | while (peer) { | |
321 | prev = peer; | |
322 | peer = peer->next; | |
323 | ibss_rsn_free(prev); | |
324 | } | |
325 | ||
326 | wpa_deinit(ibss_rsn->auth_group); | |
327 | os_free(ibss_rsn); | |
328 | ||
329 | } |