source: mainline/uspace/lib/ieee80211/src/ieee80211.c@ 02246b8

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 02246b8 was e71c023, checked in by Jiří Zárevúcky <jiri.zarevucky@…>, 7 years ago

Fix stack corruption in ieee80211 (courtesy of hosted mode diagnostics).

  • Property mode set to 100644
File size: 47.8 KB
Line 
1/*
2 * Copyright (c) 2015 Jan Kolarik
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libieee80211
30 * @{
31 */
32
33/** @file ieee80211.c
34 *
35 * IEEE 802.11 interface implementation.
36 */
37
38#include <stdio.h>
39#include <crypto.h>
40#include <str.h>
41#include <macros.h>
42#include <errno.h>
43#include <ieee80211.h>
44#include <ieee80211_impl.h>
45#include <ieee80211_iface_impl.h>
46#include <ieee80211_private.h>
47#include <ops/ieee80211.h>
48
49#define IEEE80211_DATA_RATES_SIZE 8
50#define IEEE80211_EXT_DATA_RATES_SIZE 4
51
52#define ATOMIC_GET(state)
53
54/** Frame encapsulation used in IEEE 802.11. */
55static const uint8_t rfc1042_header[] = {
56 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00
57};
58
59/** Broadcast MAC address. */
60static const uint8_t ieee80211_broadcast_mac_addr[] = {
61 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
62};
63
64/** Check data frame.
65 *
66 * @param frame_ctrl Frame control field in little endian (!).
67 *
68 * @return True if it is data frame, otherwise false.
69 *
70 */
71inline bool ieee80211_is_data_frame(uint16_t frame_ctrl)
72{
73 frame_ctrl = uint16_t_le2host(frame_ctrl);
74
75 return (frame_ctrl & IEEE80211_FRAME_CTRL_FRAME_TYPE) ==
76 IEEE80211_DATA_FRAME;
77}
78
79/** Check management frame.
80 *
81 * @param frame_ctrl Frame control field in little endian (!).
82 *
83 * @return True if it is management frame, otherwise false.
84 *
85 */
86inline bool ieee80211_is_mgmt_frame(uint16_t frame_ctrl)
87{
88 frame_ctrl = uint16_t_le2host(frame_ctrl);
89
90 return (frame_ctrl & IEEE80211_FRAME_CTRL_FRAME_TYPE) ==
91 IEEE80211_MGMT_FRAME;
92}
93
94/** Check management beacon frame.
95 *
96 * @param frame_ctrl Frame control field in little endian (!).
97 *
98 * @return True if it is beacon frame, otherwise false.
99 *
100 */
101inline bool ieee80211_is_beacon_frame(uint16_t frame_ctrl)
102{
103 frame_ctrl = uint16_t_le2host(frame_ctrl);
104
105 return (frame_ctrl & IEEE80211_FRAME_CTRL_FRAME_SUBTYPE) ==
106 IEEE80211_MGMT_BEACON_FRAME;
107}
108
109/** Check management probe response frame.
110 *
111 * @param frame_ctrl Frame control field in little endian (!).
112 *
113 * @return True if it is probe resp frame, otherwise false.
114 *
115 */
116inline bool ieee80211_is_probe_response_frame(uint16_t frame_ctrl)
117{
118 frame_ctrl = uint16_t_le2host(frame_ctrl);
119
120 return (frame_ctrl & IEEE80211_FRAME_CTRL_FRAME_SUBTYPE) ==
121 IEEE80211_MGMT_PROBE_RESP_FRAME;
122}
123
124/** Check management authentication frame.
125 *
126 * @param frame_ctrl Frame control field in little endian (!).
127 *
128 * @return True if it is auth frame, otherwise false.
129 *
130 */
131inline bool ieee80211_is_auth_frame(uint16_t frame_ctrl)
132{
133 frame_ctrl = uint16_t_le2host(frame_ctrl);
134
135 return (frame_ctrl & IEEE80211_FRAME_CTRL_FRAME_SUBTYPE) ==
136 IEEE80211_MGMT_AUTH_FRAME;
137}
138
139/** Check management association response frame.
140 *
141 * @param frame_ctrl Frame control field in little endian (!).
142 *
143 * @return True if it is assoc resp frame, otherwise false.
144 *
145 */
146inline bool ieee80211_is_assoc_response_frame(uint16_t frame_ctrl)
147{
148 frame_ctrl = uint16_t_le2host(frame_ctrl);
149
150 return (frame_ctrl & IEEE80211_FRAME_CTRL_FRAME_SUBTYPE) ==
151 IEEE80211_MGMT_ASSOC_RESP_FRAME;
152}
153
154/** Check data frame "to distribution system" direction.
155 *
156 * @param frame_ctrl Frame control field in little endian (!).
157 *
158 * @return True if it is TODS frame, otherwise false.
159 *
160 */
161inline bool ieee80211_is_tods_frame(uint16_t frame_ctrl)
162{
163 frame_ctrl = uint16_t_le2host(frame_ctrl);
164
165 return (frame_ctrl & IEEE80211_FRAME_CTRL_TODS);
166}
167
168/** Check data frame "from distribution system" direction.
169 *
170 * @param frame_ctrl Frame control field in little endian (!).
171 *
172 * @return True if it is FROMDS frame, otherwise false.
173 *
174 */
175inline bool ieee80211_is_fromds_frame(uint16_t frame_ctrl)
176{
177 frame_ctrl = uint16_t_le2host(frame_ctrl);
178
179 return (frame_ctrl & IEEE80211_FRAME_CTRL_FROMDS);
180}
181
182/** Check if it is data frame containing payload data.
183 *
184 * @param frame_ctrl Frame control field in little endian (!).
185 *
186 * @return True if it has payload data, otherwise false.
187 *
188 */
189static inline bool ieee80211_has_data_frame(uint16_t frame_ctrl)
190{
191 frame_ctrl = uint16_t_le2host(frame_ctrl);
192
193 return (frame_ctrl & (IEEE80211_FRAME_CTRL_FRAME_TYPE | 0x40)) ==
194 IEEE80211_DATA_FRAME;
195}
196
197/** Check if it is encrypted frame.
198 *
199 * @param frame_ctrl Frame control field in little endian (!).
200 *
201 * @return True if the frame is encrypted, otherwise false.
202 *
203 */
204static inline bool ieee80211_is_encrypted_frame(uint16_t frame_ctrl)
205{
206 frame_ctrl = uint16_t_le2host(frame_ctrl);
207
208 return (frame_ctrl & IEEE80211_FRAME_CTRL_PROTECTED);
209}
210
211/** Check if PAE packet is EAPOL-Key frame.
212 *
213 * @param key_frame Pointer to start of EAPOL frame.
214 *
215 * @return True if it is EAPOL-Key frame, otherwise false.
216 *
217 */
218static inline bool
219ieee80211_is_eapol_key_frame(ieee80211_eapol_key_frame_t *key_frame)
220{
221 return (key_frame->packet_type == IEEE80211_EAPOL_KEY);
222}
223
224/** Generate packet sequence number.
225 *
226 * @param ieee80211_dev IEEE 802.11 device.
227 *
228 * @return True if it has payload data, otherwise false.
229 *
230 */
231static uint16_t ieee80211_get_sequence_number(ieee80211_dev_t *ieee80211_dev)
232{
233 uint16_t ret_val = ieee80211_dev->sequence_number;
234 ieee80211_dev->sequence_number += (1 << 4);
235
236 return ret_val;
237}
238
239/** Get driver-specific structure for IEEE 802.11 device.
240 *
241 * @param ieee80211_dev IEEE 802.11 device.
242 *
243 * @return Driver-specific structure.
244 *
245 */
246void *ieee80211_get_specific(ieee80211_dev_t *ieee80211_dev)
247{
248 return ieee80211_dev->specific;
249}
250
251/** Set driver-specific structure for IEEE 802.11 device.
252 *
253 * @param ieee80211_dev IEEE 802.11 device.
254 * @param specific Driver-specific structure.
255 *
256 */
257void ieee80211_set_specific(ieee80211_dev_t *ieee80211_dev,
258 void *specific)
259{
260 ieee80211_dev->specific = specific;
261}
262
263/** Get related DDF device.
264 *
265 * @param ieee80211_dev IEEE 802.11 device.
266 *
267 * @return DDF device.
268 *
269 */
270ddf_dev_t *ieee80211_get_ddf_dev(ieee80211_dev_t *ieee80211_dev)
271{
272 return ieee80211_dev->ddf_dev;
273}
274
275/** Query current operating mode of IEEE 802.11 device.
276 *
277 * @param ieee80211_dev IEEE 802.11 device.
278 *
279 * @return Current IEEE 802.11 operating mode.
280 *
281 */
282ieee80211_operating_mode_t
283ieee80211_query_current_op_mode(ieee80211_dev_t *ieee80211_dev)
284{
285 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
286 ieee80211_operating_mode_t op_mode = ieee80211_dev->current_op_mode;
287 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
288
289 return op_mode;
290}
291
292/** Query current frequency of IEEE 802.11 device.
293 *
294 * @param ieee80211_dev IEEE 802.11 device.
295 *
296 * @return Current device operating frequency.
297 *
298 */
299uint16_t ieee80211_query_current_freq(ieee80211_dev_t *ieee80211_dev)
300{
301 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
302 uint16_t current_freq = ieee80211_dev->current_freq;
303 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
304
305 return current_freq;
306}
307
308/** Query BSSID the device is connected to.
309 *
310 * Note: Expecting locked results_mutex.
311 *
312 * @param ieee80211_dev IEEE 802.11 device.
313 * @param bssid Pointer to structure where should be stored BSSID.
314 *
315 */
316void ieee80211_query_bssid(ieee80211_dev_t *ieee80211_dev,
317 nic_address_t *bssid)
318{
319 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
320
321 if (bssid) {
322 ieee80211_scan_result_link_t *res_link =
323 ieee80211_dev->bssid_info.res_link;
324
325 if (res_link) {
326 memcpy(bssid, &res_link->scan_result.bssid,
327 sizeof(nic_address_t));
328 } else {
329 nic_address_t broadcast_addr;
330 memcpy(broadcast_addr.address,
331 ieee80211_broadcast_mac_addr, ETH_ADDR);
332 memcpy(bssid, &broadcast_addr, sizeof(nic_address_t));
333 }
334 }
335
336 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
337}
338
339/** Get AID of network we are connected to.
340 *
341 * @param ieee80211_dev IEEE 802.11 device.
342 *
343 * @return AID.
344 *
345 */
346uint16_t ieee80211_get_aid(ieee80211_dev_t *ieee80211_dev)
347{
348 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
349 uint16_t aid = ieee80211_dev->bssid_info.aid;
350 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
351
352 return aid;
353}
354
355/** Get pairwise security suite used for HW encryption.
356 *
357 * @param ieee80211_dev IEEE 802.11 device.
358 *
359 * @return Security suite indicator.
360 *
361 */
362int ieee80211_get_pairwise_security(ieee80211_dev_t *ieee80211_dev)
363{
364 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
365 ieee80211_scan_result_link_t *auth_link =
366 ieee80211_dev->bssid_info.res_link;
367 int suite = auth_link->scan_result.security.pair_alg;
368 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
369
370 return suite;
371}
372
373/** Check if IEEE 802.11 device is connected to network.
374 *
375 * @param ieee80211_dev IEEE 802.11 device.
376 *
377 * @return True if device is connected to network, otherwise false.
378 *
379 */
380bool ieee80211_is_connected(ieee80211_dev_t *ieee80211_dev)
381{
382 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
383 bool conn_state =
384 ieee80211_dev->current_auth_phase == IEEE80211_AUTH_CONNECTED;
385 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
386
387 return conn_state;
388}
389
390void ieee80211_set_auth_phase(ieee80211_dev_t *ieee80211_dev,
391 ieee80211_auth_phase_t auth_phase)
392{
393 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
394 ieee80211_dev->current_auth_phase = auth_phase;
395 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
396}
397
398ieee80211_auth_phase_t ieee80211_get_auth_phase(ieee80211_dev_t *ieee80211_dev)
399{
400 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
401 ieee80211_auth_phase_t conn_state = ieee80211_dev->current_auth_phase;
402 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
403
404 return conn_state;
405}
406
407void ieee80211_set_connect_request(ieee80211_dev_t *ieee80211_dev)
408{
409 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
410 ieee80211_dev->pending_conn_req = true;
411 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
412}
413
414bool ieee80211_pending_connect_request(ieee80211_dev_t *ieee80211_dev)
415{
416 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
417 bool conn_request = ieee80211_dev->pending_conn_req;
418 ieee80211_dev->pending_conn_req = false;
419 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
420
421 return conn_request;
422}
423
424/** Report current operating mode for IEEE 802.11 device.
425 *
426 * @param ieee80211_dev IEEE 802.11 device.
427 * @param op_mode Current IEEE 802.11 operating mode.
428 *
429 */
430void ieee80211_report_current_op_mode(ieee80211_dev_t *ieee80211_dev,
431 ieee80211_operating_mode_t op_mode)
432{
433 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
434 ieee80211_dev->current_op_mode = op_mode;
435 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
436}
437
438/** Report current frequency for IEEE 802.11 device.
439 *
440 * @param ieee80211_dev IEEE 802.11 device.
441 * @param freq Current device operating frequency.
442 *
443 */
444void ieee80211_report_current_freq(ieee80211_dev_t *ieee80211_dev,
445 uint16_t freq)
446{
447 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
448 ieee80211_dev->current_freq = freq;
449 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
450}
451
452/** Check if IEEE 802.11 device is ready (fully initialized).
453 *
454 * @param ieee80211_dev IEEE 802.11 device.
455 *
456 * @return True if device is ready to work, otherwise false.
457 *
458 */
459bool ieee80211_is_ready(ieee80211_dev_t *ieee80211_dev)
460{
461 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
462 bool ready_state = ieee80211_dev->ready;
463 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
464
465 return ready_state;
466}
467
468/** Set IEEE 802.11 device to ready state.
469 *
470 * @param ieee80211_dev IEEE 802.11 device.
471 * @param ready Ready state to be set.
472 *
473 */
474void ieee80211_set_ready(ieee80211_dev_t *ieee80211_dev, bool ready)
475{
476 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
477 ieee80211_dev->ready = ready;
478 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
479}
480
481extern bool ieee80211_query_using_key(ieee80211_dev_t *ieee80211_dev)
482{
483 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
484 bool using_key = ieee80211_dev->using_hw_key;
485 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
486
487 return using_key;
488}
489
490void ieee80211_setup_key_confirm(ieee80211_dev_t *ieee80211_dev,
491 bool using_key)
492{
493 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
494 ieee80211_dev->using_hw_key = using_key;
495 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
496}
497
498static errno_t ieee80211_scan(void *arg)
499{
500 assert(arg);
501
502 ieee80211_dev_t *ieee80211_dev = (ieee80211_dev_t *) arg;
503
504 while (true) {
505 ieee80211_dev->ops->scan(ieee80211_dev);
506 fibril_usleep(SCAN_PERIOD_USEC);
507 }
508
509 return EOK;
510}
511
512/** Implementation of NIC open callback for IEEE 802.11 devices.
513 *
514 * @param fun NIC function.
515 *
516 * @return EOK if succeed, error code otherwise.
517 *
518 */
519static errno_t ieee80211_open(ddf_fun_t *fun)
520{
521 nic_t *nic_data = nic_get_from_ddf_fun(fun);
522 ieee80211_dev_t *ieee80211_dev = nic_get_specific(nic_data);
523
524 if (ieee80211_dev->started)
525 return EOK;
526
527 ieee80211_dev->started = true;
528
529 errno_t rc = ieee80211_dev->ops->start(ieee80211_dev);
530 if (rc != EOK)
531 return rc;
532
533 /* Add scanning fibril. */
534 fid_t fibril = fibril_create(ieee80211_scan, ieee80211_dev);
535 if (fibril == 0)
536 return ENOMEM;
537
538 fibril_add_ready(fibril);
539
540 return EOK;
541}
542
543/** Send frame handler.
544 *
545 * @param nic Pointer to NIC device.
546 * @param data Data buffer.
547 * @param size Data buffer size.
548 *
549 */
550static void ieee80211_send_frame(nic_t *nic, void *data, size_t size)
551{
552 ieee80211_dev_t *ieee80211_dev = (ieee80211_dev_t *)
553 nic_get_specific(nic);
554
555 ieee80211_auth_phase_t auth_phase =
556 ieee80211_get_auth_phase(ieee80211_dev);
557 if ((auth_phase != IEEE80211_AUTH_ASSOCIATED) &&
558 (auth_phase != IEEE80211_AUTH_CONNECTED))
559 return;
560
561 ieee80211_scan_result_t *auth_data =
562 &ieee80211_dev->bssid_info.res_link->scan_result;
563
564 /* We drop part of IEEE 802.3 ethernet header. */
565 size_t drop_bytes = sizeof(eth_header_t) - 2;
566
567 size_t complete_size = (size - drop_bytes) +
568 sizeof(ieee80211_data_header_t) +
569 ARRAY_SIZE(rfc1042_header);
570
571 /* Init crypto data. */
572 bool add_mic = false;
573 const size_t max_head_space = max(IEEE80211_TKIP_HEADER_LENGTH,
574 IEEE80211_CCMP_HEADER_LENGTH);
575 size_t head_space = 0, mic_space = 0;
576 uint16_t crypto = 0;
577 uint8_t head_data[max_head_space];
578 memset(head_data, 0, max_head_space);
579
580 // TODO: Distinguish used key (pair/group) by dest address ?
581 if (ieee80211_query_using_key(ieee80211_dev)) {
582 int sec_suite = auth_data->security.pair_alg;
583 switch (sec_suite) {
584 case IEEE80211_SECURITY_SUITE_TKIP:
585 head_space = IEEE80211_TKIP_HEADER_LENGTH;
586 mic_space = MIC_LENGTH;
587 add_mic = true;
588 break;
589 case IEEE80211_SECURITY_SUITE_CCMP:
590 head_space = IEEE80211_CCMP_HEADER_LENGTH;
591 head_data[3] = 0x20;
592 break;
593 default:
594 break;
595 }
596
597 crypto = uint16_t_le2host(IEEE80211_FRAME_CTRL_PROTECTED);
598 }
599
600 complete_size += head_space + mic_space;
601
602 void *complete_buffer = malloc(complete_size);
603 if (!complete_buffer)
604 return;
605
606 memset(complete_buffer, 0, complete_size);
607
608 if (head_space)
609 memcpy(complete_buffer + sizeof(ieee80211_data_header_t),
610 head_data, head_space);
611
612 memcpy(complete_buffer + sizeof(ieee80211_data_header_t) + head_space,
613 rfc1042_header, ARRAY_SIZE(rfc1042_header));
614
615 memcpy(complete_buffer + sizeof(ieee80211_data_header_t) +
616 ARRAY_SIZE(rfc1042_header) + head_space,
617 data + drop_bytes, size - drop_bytes);
618
619 ieee80211_data_header_t *data_header =
620 (ieee80211_data_header_t *) complete_buffer;
621 data_header->frame_ctrl =
622 uint16_t_le2host(IEEE80211_DATA_FRAME) |
623 uint16_t_le2host(IEEE80211_DATA_DATA_FRAME) |
624 uint16_t_le2host(IEEE80211_FRAME_CTRL_TODS) |
625 crypto;
626 data_header->seq_ctrl = ieee80211_get_sequence_number(ieee80211_dev);
627
628 /* BSSID, SA, DA. */
629 memcpy(data_header->address1, auth_data->bssid.address, ETH_ADDR);
630 memcpy(data_header->address2, data + ETH_ADDR, ETH_ADDR);
631 memcpy(data_header->address3, data, ETH_ADDR);
632
633 if (add_mic) {
634 size_t size_wo_mic = complete_size - MIC_LENGTH;
635 uint8_t *tx_mic = ieee80211_dev->bssid_info.ptk +
636 TK_OFFSET + IEEE80211_TKIP_TX_MIC_OFFSET;
637 ieee80211_michael_mic(tx_mic, complete_buffer, size_wo_mic,
638 complete_buffer + size_wo_mic);
639 }
640
641 ieee80211_dev->ops->tx_handler(ieee80211_dev,
642 complete_buffer, complete_size);
643
644 free(complete_buffer);
645}
646
647/** Fill out IEEE 802.11 device functions implementations.
648 *
649 * @param ieee80211_dev IEEE 802.11 device.
650 * @param ieee80211_ops Callbacks implementation.
651 * @param ieee80211_iface Interface functions implementation.
652 * @param nic_iface NIC interface functions implementation.
653 * @param nic_dev_ops NIC device functions implementation.
654 *
655 * @return EINVAL when missing pointer to ieee80211_ops
656 * or ieee80211_iface, otherwise EOK.
657 *
658 */
659static errno_t ieee80211_implement(ieee80211_dev_t *ieee80211_dev,
660 ieee80211_ops_t *ieee80211_ops, ieee80211_iface_t *ieee80211_iface,
661 nic_iface_t *nic_iface, ddf_dev_ops_t *nic_dev_ops)
662{
663 if (ieee80211_ops) {
664 if (!ieee80211_ops->start)
665 ieee80211_ops->start = ieee80211_start_impl;
666
667 if (!ieee80211_ops->tx_handler)
668 ieee80211_ops->tx_handler = ieee80211_tx_handler_impl;
669
670 if (!ieee80211_ops->set_freq)
671 ieee80211_ops->set_freq = ieee80211_set_freq_impl;
672
673 if (!ieee80211_ops->bssid_change)
674 ieee80211_ops->bssid_change = ieee80211_bssid_change_impl;
675
676 if (!ieee80211_ops->key_config)
677 ieee80211_ops->key_config = ieee80211_key_config_impl;
678
679 if (!ieee80211_ops->scan)
680 ieee80211_ops->scan = ieee80211_scan_impl;
681 } else
682 return EINVAL;
683
684 ieee80211_dev->ops = ieee80211_ops;
685
686 if (ieee80211_iface) {
687 if (nic_dev_ops)
688 if (!nic_dev_ops->interfaces[IEEE80211_DEV_IFACE])
689 nic_dev_ops->interfaces[IEEE80211_DEV_IFACE] =
690 ieee80211_iface;
691
692 if (!ieee80211_iface->get_scan_results)
693 ieee80211_iface->get_scan_results =
694 ieee80211_get_scan_results_impl;
695
696 if (!ieee80211_iface->connect)
697 ieee80211_iface->connect = ieee80211_connect_impl;
698
699 if (!ieee80211_iface->disconnect)
700 ieee80211_iface->disconnect = ieee80211_disconnect_impl;
701 } else
702 return EINVAL;
703
704 if (nic_dev_ops) {
705 if (!nic_dev_ops->open)
706 nic_dev_ops->open = ieee80211_open;
707 } else
708 return EINVAL;
709
710 ieee80211_dev->iface = ieee80211_iface;
711
712 nic_driver_implement(NULL, nic_dev_ops, nic_iface);
713
714 return EOK;
715}
716
717/** Allocate IEEE802.11 device structure.
718 *
719 * @return Pointer to allocated IEEE802.11 device structure.
720 *
721 */
722ieee80211_dev_t *ieee80211_device_create(void)
723{
724 return calloc(1, sizeof(ieee80211_dev_t));
725}
726
727/** Initialize an IEEE802.11 framework structure.
728 *
729 * @param ieee80211_dev Device structure to initialize.
730 * @param ddf_dev Pointer to backing DDF device structure.
731 *
732 * @return EOK if succeed, error code otherwise.
733 *
734 */
735errno_t ieee80211_device_init(ieee80211_dev_t *ieee80211_dev, ddf_dev_t *ddf_dev)
736{
737 ieee80211_dev->ddf_dev = ddf_dev;
738 ieee80211_dev->started = false;
739 ieee80211_dev->ready = false;
740 ieee80211_dev->using_hw_key = false;
741 ieee80211_dev->pending_conn_req = false;
742 ieee80211_dev->current_op_mode = IEEE80211_OPMODE_STATION;
743 ieee80211_dev->current_auth_phase = IEEE80211_AUTH_DISCONNECTED;
744
745 memcpy(ieee80211_dev->bssid_mask.address, ieee80211_broadcast_mac_addr,
746 ETH_ADDR);
747
748 ieee80211_scan_result_list_init(&ieee80211_dev->ap_list);
749
750 fibril_mutex_initialize(&ieee80211_dev->scan_mutex);
751 fibril_mutex_initialize(&ieee80211_dev->gen_mutex);
752 fibril_condvar_initialize(&ieee80211_dev->gen_cond);
753
754 /* Bind NIC to device */
755 nic_t *nic = nic_create_and_bind(ddf_dev);
756 if (!nic)
757 return ENOMEM;
758
759 nic_set_specific(nic, ieee80211_dev);
760
761 return EOK;
762}
763
764/** IEEE802.11 WiFi framework initialization.
765 *
766 * @param ieee80211_dev Device structure to initialize.
767 * @param ieee80211_ops Structure with implemented IEEE802.11
768 * device operations.
769 * @param ieee80211_iface Structure with implemented IEEE802.11
770 * interface operations.
771 *
772 * @return EOK if succeed, error code otherwise.
773 *
774 */
775errno_t ieee80211_init(ieee80211_dev_t *ieee80211_dev,
776 ieee80211_ops_t *ieee80211_ops, ieee80211_iface_t *ieee80211_iface,
777 nic_iface_t *ieee80211_nic_iface, ddf_dev_ops_t *ieee80211_nic_dev_ops)
778{
779 errno_t rc = ieee80211_implement(ieee80211_dev,
780 ieee80211_ops, ieee80211_iface,
781 ieee80211_nic_iface, ieee80211_nic_dev_ops);
782 if (rc != EOK)
783 return rc;
784
785 nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
786
787 /* TODO: Set NIC handlers here. */
788 nic_set_send_frame_handler(nic, ieee80211_send_frame);
789
790 ddf_fun_t *fun = ddf_fun_create(ieee80211_dev->ddf_dev, fun_exposed,
791 "port0");
792 if (fun == NULL)
793 return EINVAL;
794
795 nic_set_ddf_fun(nic, fun);
796 ddf_fun_set_ops(fun, ieee80211_nic_dev_ops);
797
798 rc = ddf_fun_bind(fun);
799 if (rc != EOK) {
800 ddf_fun_destroy(fun);
801 return rc;
802 }
803
804 rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC);
805 if (rc != EOK) {
806 ddf_fun_unbind(fun);
807 return rc;
808 }
809
810 rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_IEEE80211);
811 if (rc != EOK) {
812 ddf_fun_unbind(fun);
813 return rc;
814 }
815
816 return EOK;
817}
818
819/** Convert frequency value to channel number.
820 *
821 * @param freq IEEE 802.11 operating frequency.
822 *
823 * @return Operating channel number.
824 *
825 */
826static uint8_t ieee80211_freq_to_channel(uint16_t freq)
827{
828 return (freq - IEEE80211_FIRST_FREQ) / IEEE80211_CHANNEL_GAP + 1;
829}
830
831static void ieee80211_prepare_ie_header(void **ie_header,
832 uint8_t id, uint8_t length, void *data)
833{
834 ieee80211_ie_header_t *header =
835 (ieee80211_ie_header_t *) *ie_header;
836
837 header->element_id = id;
838 header->length = length;
839
840 memcpy(*ie_header + sizeof(ieee80211_ie_header_t), data, length);
841
842 *ie_header = (void *) ((void *) header +
843 sizeof(ieee80211_ie_header_t) + length);
844}
845
846/** Probe request implementation.
847 *
848 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
849 * @param ssid Probing SSID or NULL if broadcast.
850 *
851 * @return EOK if succeed, error code otherwise.
852 *
853 */
854errno_t ieee80211_probe_request(ieee80211_dev_t *ieee80211_dev, char *ssid)
855{
856 nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
857 nic_address_t nic_address;
858 nic_query_address(nic, &nic_address);
859
860 size_t ssid_data_size = (ssid != NULL) ? str_size(ssid) : 0;
861 size_t channel_data_size = 1;
862
863 uint8_t channel =
864 ieee80211_freq_to_channel(ieee80211_dev->current_freq);
865
866 /*
867 * 4 headers - (ssid, rates, ext rates, current channel)
868 * and their data lengths.
869 */
870 size_t payload_size =
871 sizeof(ieee80211_ie_header_t) * 4 +
872 ssid_data_size +
873 IEEE80211_DATA_RATES_SIZE + IEEE80211_EXT_DATA_RATES_SIZE +
874 channel_data_size;
875
876 size_t buffer_size = sizeof(ieee80211_mgmt_header_t) + payload_size;
877 void *buffer = malloc(buffer_size);
878 if (!buffer)
879 return ENOMEM;
880
881 memset(buffer, 0, buffer_size);
882
883 ieee80211_mgmt_header_t *mgmt_header =
884 (ieee80211_mgmt_header_t *) buffer;
885
886 mgmt_header->frame_ctrl =
887 host2uint16_t_le(IEEE80211_MGMT_FRAME |
888 IEEE80211_MGMT_PROBE_REQ_FRAME);
889 memcpy(mgmt_header->dest_addr, ieee80211_broadcast_mac_addr, ETH_ADDR);
890 memcpy(mgmt_header->src_addr, nic_address.address, ETH_ADDR);
891 memcpy(mgmt_header->bssid, ieee80211_broadcast_mac_addr, ETH_ADDR);
892 mgmt_header->seq_ctrl =
893 host2uint16_t_le(ieee80211_get_sequence_number(ieee80211_dev));
894
895 /* Jump to payload. */
896 void *it = (void *) buffer + sizeof(ieee80211_mgmt_header_t);
897 ieee80211_prepare_ie_header(&it, IEEE80211_SSID_IE, ssid_data_size,
898 (void *) ssid);
899 ieee80211_prepare_ie_header(&it, IEEE80211_RATES_IE,
900 IEEE80211_DATA_RATES_SIZE, (void *) &ieee80211bg_data_rates);
901 ieee80211_prepare_ie_header(&it, IEEE80211_EXT_RATES_IE,
902 IEEE80211_EXT_DATA_RATES_SIZE,
903 (void *) &ieee80211bg_data_rates[IEEE80211_DATA_RATES_SIZE]);
904 ieee80211_prepare_ie_header(&it, IEEE80211_CHANNEL_IE,
905 channel_data_size, (void *) &channel);
906
907 ieee80211_dev->ops->tx_handler(ieee80211_dev, buffer, buffer_size);
908
909 free(buffer);
910
911 return EOK;
912}
913
914/** IEEE 802.11 authentication implementation.
915 *
916 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
917 *
918 * @return EOK if succeed, error code otherwise.
919 *
920 */
921errno_t ieee80211_authenticate(ieee80211_dev_t *ieee80211_dev)
922{
923 nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
924 nic_address_t nic_address;
925 nic_query_address(nic, &nic_address);
926
927 ieee80211_scan_result_t *auth_data =
928 &ieee80211_dev->bssid_info.res_link->scan_result;
929
930 size_t buffer_size = sizeof(ieee80211_mgmt_header_t) +
931 sizeof(ieee80211_auth_body_t);
932
933 void *buffer = malloc(buffer_size);
934 if (!buffer)
935 return ENOMEM;
936
937 memset(buffer, 0, buffer_size);
938
939 ieee80211_mgmt_header_t *mgmt_header =
940 (ieee80211_mgmt_header_t *) buffer;
941
942 mgmt_header->frame_ctrl =
943 host2uint16_t_le(IEEE80211_MGMT_FRAME |
944 IEEE80211_MGMT_AUTH_FRAME);
945 memcpy(mgmt_header->dest_addr, auth_data->bssid.address, ETH_ADDR);
946 memcpy(mgmt_header->src_addr, nic_address.address, ETH_ADDR);
947 memcpy(mgmt_header->bssid, auth_data->bssid.address, ETH_ADDR);
948
949 ieee80211_auth_body_t *auth_body =
950 (ieee80211_auth_body_t *)
951 (buffer + sizeof(ieee80211_mgmt_header_t));
952 auth_body->auth_alg = host2uint16_t_le(0);
953 auth_body->auth_trans_no = host2uint16_t_le(1);
954
955 ieee80211_dev->ops->tx_handler(ieee80211_dev, buffer, buffer_size);
956
957 free(buffer);
958
959 return EOK;
960}
961
962/** IEEE 802.11 association implementation.
963 *
964 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
965 * @param password Passphrase to be used in encrypted communication
966 * or NULL for open networks.
967 *
968 * @return EOK if succeed, error code otherwise.
969 *
970 */
971errno_t ieee80211_associate(ieee80211_dev_t *ieee80211_dev, char *password)
972{
973 nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
974 nic_address_t nic_address;
975 nic_query_address(nic, &nic_address);
976
977 ieee80211_scan_result_link_t *auth_link =
978 ieee80211_dev->bssid_info.res_link;
979
980 ieee80211_scan_result_t *auth_data = &auth_link->scan_result;
981
982 size_t ssid_data_size = str_size(auth_data->ssid);
983
984 size_t payload_size =
985 sizeof(ieee80211_ie_header_t) * 3 +
986 ssid_data_size +
987 IEEE80211_DATA_RATES_SIZE +
988 IEEE80211_EXT_DATA_RATES_SIZE;
989
990 size_t buffer_size =
991 sizeof(ieee80211_mgmt_header_t) +
992 sizeof(ieee80211_assoc_req_body_t) +
993 payload_size;
994
995 if ((auth_data->security.type == IEEE80211_SECURITY_WPA) ||
996 (auth_data->security.type == IEEE80211_SECURITY_WPA2))
997 buffer_size += auth_link->auth_ie_len;
998
999 void *buffer = malloc(buffer_size);
1000 if (!buffer)
1001 return ENOMEM;
1002
1003 memset(buffer, 0, buffer_size);
1004
1005 ieee80211_mgmt_header_t *mgmt_header =
1006 (ieee80211_mgmt_header_t *) buffer;
1007
1008 mgmt_header->frame_ctrl =
1009 host2uint16_t_le(IEEE80211_MGMT_FRAME |
1010 IEEE80211_MGMT_ASSOC_REQ_FRAME);
1011 memcpy(mgmt_header->dest_addr, auth_data->bssid.address, ETH_ADDR);
1012 memcpy(mgmt_header->src_addr, nic_address.address, ETH_ADDR);
1013 memcpy(mgmt_header->bssid, auth_data->bssid.address, ETH_ADDR);
1014
1015 ieee80211_assoc_req_body_t *assoc_body =
1016 (ieee80211_assoc_req_body_t *)
1017 (buffer + sizeof(ieee80211_mgmt_header_t));
1018 assoc_body->listen_interval = host2uint16_t_le(1);
1019
1020 /* Jump to payload. */
1021 void *it = buffer + sizeof(ieee80211_mgmt_header_t) +
1022 sizeof(ieee80211_assoc_req_body_t);
1023 ieee80211_prepare_ie_header(&it, IEEE80211_SSID_IE,
1024 ssid_data_size, (void *) auth_data->ssid);
1025 ieee80211_prepare_ie_header(&it, IEEE80211_RATES_IE,
1026 IEEE80211_DATA_RATES_SIZE, (void *) &ieee80211bg_data_rates);
1027 ieee80211_prepare_ie_header(&it, IEEE80211_EXT_RATES_IE,
1028 IEEE80211_EXT_DATA_RATES_SIZE,
1029 (void *) &ieee80211bg_data_rates[IEEE80211_DATA_RATES_SIZE]);
1030
1031 if (auth_data->security.type != IEEE80211_SECURITY_OPEN)
1032 assoc_body->capability |= host2uint16_t_le(CAP_SECURITY);
1033
1034 if ((auth_data->security.type == IEEE80211_SECURITY_WPA) ||
1035 (auth_data->security.type == IEEE80211_SECURITY_WPA2))
1036 memcpy(it, auth_link->auth_ie, auth_link->auth_ie_len);
1037
1038 ieee80211_dev->ops->tx_handler(ieee80211_dev, buffer, buffer_size);
1039
1040 /*
1041 * Save password to be used in eventual authentication handshake.
1042 */
1043 memset(ieee80211_dev->bssid_info.password, 0, IEEE80211_MAX_PASSW_LEN);
1044 memcpy(ieee80211_dev->bssid_info.password, password,
1045 str_size(password));
1046
1047 free(buffer);
1048
1049 return EOK;
1050}
1051
1052/** IEEE 802.11 deauthentication implementation.
1053 *
1054 * Note: Expecting locked results_mutex or scan_mutex.
1055 *
1056 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
1057 *
1058 * @return EOK if succeed, error code otherwise.
1059 *
1060 */
1061errno_t ieee80211_deauthenticate(ieee80211_dev_t *ieee80211_dev)
1062{
1063 ieee80211_scan_result_t *auth_data =
1064 &ieee80211_dev->bssid_info.res_link->scan_result;
1065
1066 nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
1067 nic_address_t nic_address;
1068 nic_query_address(nic, &nic_address);
1069
1070 size_t buffer_size = sizeof(ieee80211_mgmt_header_t) +
1071 sizeof(ieee80211_deauth_body_t);
1072
1073 void *buffer = malloc(buffer_size);
1074 if (!buffer)
1075 return ENOMEM;
1076
1077 memset(buffer, 0, buffer_size);
1078
1079 ieee80211_mgmt_header_t *mgmt_header =
1080 (ieee80211_mgmt_header_t *) buffer;
1081
1082 mgmt_header->frame_ctrl =
1083 host2uint16_t_le(IEEE80211_MGMT_FRAME |
1084 IEEE80211_MGMT_DEAUTH_FRAME);
1085 memcpy(mgmt_header->dest_addr, auth_data->bssid.address, ETH_ADDR);
1086 memcpy(mgmt_header->src_addr, nic_address.address, ETH_ADDR);
1087 memcpy(mgmt_header->bssid, auth_data->bssid.address, ETH_ADDR);
1088
1089 ieee80211_dev->ops->tx_handler(ieee80211_dev, buffer, buffer_size);
1090
1091 free(buffer);
1092
1093 ieee80211_dev->bssid_info.res_link = NULL;
1094 ieee80211_dev->ops->bssid_change(ieee80211_dev, false);
1095
1096 if (ieee80211_query_using_key(ieee80211_dev))
1097 ieee80211_dev->ops->key_config(ieee80211_dev, NULL, false);
1098
1099 ieee80211_set_auth_phase(ieee80211_dev, IEEE80211_AUTH_DISCONNECTED);
1100
1101 return EOK;
1102}
1103
1104static void ieee80211_process_auth_info(ieee80211_scan_result_link_t *ap_data,
1105 void *buffer)
1106{
1107 uint8_t *it = (uint8_t *) buffer;
1108
1109 uint16_t *version = (uint16_t *) it;
1110 if (uint16_t_le2host(*version) != 0x1) {
1111 ap_data->scan_result.security.type = -1;
1112 return;
1113 }
1114
1115 it += sizeof(uint16_t);
1116
1117 uint32_t group_cipher = *(it + 3);
1118 switch (group_cipher) {
1119 case IEEE80211_AUTH_CIPHER_TKIP:
1120 ap_data->scan_result.security.group_alg =
1121 IEEE80211_SECURITY_SUITE_TKIP;
1122 break;
1123 case IEEE80211_AUTH_CIPHER_CCMP:
1124 ap_data->scan_result.security.group_alg =
1125 IEEE80211_SECURITY_SUITE_CCMP;
1126 break;
1127 default:
1128 ap_data->scan_result.security.group_alg = -1;
1129 }
1130
1131 it += 4 * sizeof(uint8_t);
1132
1133 uint16_t *pairwise_count = (uint16_t *) it;
1134 uint32_t pairwise_cipher = *(it + sizeof(uint16_t) + 3);
1135 switch (pairwise_cipher) {
1136 case IEEE80211_AUTH_CIPHER_TKIP:
1137 ap_data->scan_result.security.pair_alg =
1138 IEEE80211_SECURITY_SUITE_TKIP;
1139 break;
1140 case IEEE80211_AUTH_CIPHER_CCMP:
1141 ap_data->scan_result.security.pair_alg =
1142 IEEE80211_SECURITY_SUITE_CCMP;
1143 break;
1144 default:
1145 ap_data->scan_result.security.pair_alg = -1;
1146 }
1147
1148 it += 2 * sizeof(uint16_t) +
1149 uint16_t_le2host(*pairwise_count) * sizeof(uint32_t);
1150
1151 uint32_t auth_suite = *(it + 3);
1152 switch (auth_suite) {
1153 case IEEE80211_AUTH_AKM_PSK:
1154 ap_data->scan_result.security.auth =
1155 IEEE80211_SECURITY_AUTH_PSK;
1156 break;
1157 case IEEE80211_AUTH_AKM_8021X:
1158 ap_data->scan_result.security.auth =
1159 IEEE80211_SECURITY_AUTH_8021X;
1160 break;
1161 default:
1162 ap_data->scan_result.security.auth = -1;
1163 }
1164}
1165
1166static void copy_auth_ie(ieee80211_ie_header_t *ie_header,
1167 ieee80211_scan_result_link_t *ap_data, void *it)
1168{
1169 ap_data->auth_ie_len = ie_header->length +
1170 sizeof(ieee80211_ie_header_t);
1171
1172 memcpy(ap_data->auth_ie, it, ap_data->auth_ie_len);
1173}
1174
1175static uint8_t *ieee80211_process_ies(ieee80211_dev_t *ieee80211_dev,
1176 ieee80211_scan_result_link_t *ap_data, void *buffer, size_t buffer_size)
1177{
1178 void *it = buffer;
1179 while ((it + sizeof(ieee80211_ie_header_t)) < buffer + buffer_size) {
1180 ieee80211_ie_header_t *ie_header =
1181 (ieee80211_ie_header_t *) it;
1182 uint8_t *channel;
1183 uint32_t oui;
1184
1185 switch (ie_header->element_id) {
1186 case IEEE80211_CHANNEL_IE:
1187 if (!ap_data)
1188 break;
1189
1190 channel = (uint8_t *)
1191 (it + sizeof(ieee80211_ie_header_t));
1192 ap_data->scan_result.channel = *channel;
1193 break;
1194 case IEEE80211_RSN_IE:
1195 if (!ap_data)
1196 break;
1197
1198 ap_data->scan_result.security.type =
1199 IEEE80211_SECURITY_WPA2;
1200 ieee80211_process_auth_info(ap_data,
1201 it + sizeof(ieee80211_ie_header_t));
1202 copy_auth_ie(ie_header, ap_data, it);
1203 break;
1204 case IEEE80211_VENDOR_IE:
1205 oui = uint32be_from_seq(it +
1206 sizeof(ieee80211_ie_header_t));
1207
1208 if (oui == WPA_OUI) {
1209 if (!ap_data)
1210 break;
1211
1212 /* Prefering WPA2. */
1213 if (ap_data->scan_result.security.type ==
1214 IEEE80211_SECURITY_WPA2)
1215 break;
1216
1217 ap_data->scan_result.security.type =
1218 IEEE80211_SECURITY_WPA;
1219
1220 ieee80211_process_auth_info(ap_data,
1221 it + sizeof(ieee80211_ie_header_t) +
1222 sizeof(uint32_t));
1223 copy_auth_ie(ie_header, ap_data, it);
1224 } else if (oui == GTK_OUI) {
1225 return it +
1226 sizeof(ieee80211_ie_header_t) +
1227 sizeof(uint32_t);
1228 }
1229 }
1230
1231 it += sizeof(ieee80211_ie_header_t) + ie_header->length;
1232 }
1233
1234 return NULL;
1235}
1236
1237/** Process probe response and store results.
1238 *
1239 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
1240 * @param mgmt_header Pointer to start of management frame header.
1241 *
1242 * @return EOK if succeed, error code otherwise.
1243 *
1244 */
1245static errno_t ieee80211_process_probe_response(ieee80211_dev_t *ieee80211_dev,
1246 ieee80211_mgmt_header_t *mgmt_header, size_t buffer_size)
1247{
1248 ieee80211_beacon_start_t *beacon_body = (ieee80211_beacon_start_t *)
1249 ((void *) mgmt_header + sizeof(ieee80211_mgmt_header_t));
1250
1251 ieee80211_ie_header_t *ssid_ie_header = (ieee80211_ie_header_t *)
1252 ((void *) beacon_body + sizeof(ieee80211_beacon_start_t));
1253
1254 /* Not empty SSID. */
1255 if (ssid_ie_header->length > 0) {
1256 ieee80211_scan_result_list_t *result_list =
1257 &ieee80211_dev->ap_list;
1258
1259 uint8_t *ssid_start = (uint8_t *) ((void *) ssid_ie_header +
1260 sizeof(ieee80211_ie_header_t));
1261 char ssid[IEEE80211_MAX_SSID_LENGTH];
1262
1263 memcpy(ssid, ssid_start, ssid_ie_header->length);
1264 ssid[ssid_ie_header->length] = '\0';
1265
1266 /* Check whether SSID is already in results. */
1267 ieee80211_scan_result_list_foreach(*result_list, result) {
1268 if (!str_cmp(ssid, result->scan_result.ssid)) {
1269 result->last_beacon = time(NULL);
1270 return EOK;
1271 }
1272 }
1273
1274 /* Results are full. */
1275 if (result_list->size == IEEE80211_MAX_RESULTS_LENGTH - 1)
1276 return EOK;
1277
1278 ieee80211_scan_result_link_t *ap_data =
1279 malloc(sizeof(ieee80211_scan_result_link_t));
1280 if (!ap_data)
1281 return ENOMEM;
1282
1283 memset(ap_data, 0, sizeof(ieee80211_scan_result_link_t));
1284 link_initialize(&ap_data->link);
1285
1286 memcpy(ap_data->scan_result.bssid.address,
1287 mgmt_header->bssid, ETH_ADDR);
1288 memcpy(ap_data->scan_result.ssid, ssid,
1289 ssid_ie_header->length + 1);
1290
1291 if (uint16_t_le2host(beacon_body->capability) & CAP_SECURITY) {
1292 ap_data->scan_result.security.type =
1293 IEEE80211_SECURITY_WEP;
1294 } else {
1295 ap_data->scan_result.security.type =
1296 IEEE80211_SECURITY_OPEN;
1297 ap_data->scan_result.security.auth = -1;
1298 ap_data->scan_result.security.pair_alg = -1;
1299 ap_data->scan_result.security.group_alg = -1;
1300 }
1301
1302 void *rest_ies_start = ssid_start + ssid_ie_header->length;
1303 size_t rest_buffer_size =
1304 buffer_size -
1305 sizeof(ieee80211_mgmt_header_t) -
1306 sizeof(ieee80211_beacon_start_t) -
1307 sizeof(ieee80211_ie_header_t) -
1308 ssid_ie_header->length;
1309
1310 ieee80211_process_ies(ieee80211_dev, ap_data, rest_ies_start,
1311 rest_buffer_size);
1312
1313 ap_data->last_beacon = time(NULL);
1314
1315 fibril_mutex_lock(&ieee80211_dev->ap_list.results_mutex);
1316 ieee80211_scan_result_list_append(result_list, ap_data);
1317 fibril_mutex_unlock(&ieee80211_dev->ap_list.results_mutex);
1318 }
1319
1320 return EOK;
1321}
1322
1323/** Process authentication response.
1324 *
1325 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
1326 * @param mgmt_header Pointer to start of management frame header.
1327 *
1328 * @return EOK if succeed, error code otherwise.
1329 *
1330 */
1331static errno_t ieee80211_process_auth_response(ieee80211_dev_t *ieee80211_dev,
1332 ieee80211_mgmt_header_t *mgmt_header)
1333{
1334 ieee80211_auth_body_t *auth_body =
1335 (ieee80211_auth_body_t *)
1336 ((void *) mgmt_header + sizeof(ieee80211_mgmt_header_t));
1337
1338 if (auth_body->status != 0)
1339 ieee80211_set_auth_phase(ieee80211_dev,
1340 IEEE80211_AUTH_DISCONNECTED);
1341 else
1342 ieee80211_set_auth_phase(ieee80211_dev,
1343 IEEE80211_AUTH_AUTHENTICATED);
1344
1345 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
1346 fibril_condvar_signal(&ieee80211_dev->gen_cond);
1347 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
1348
1349 return EOK;
1350}
1351
1352/** Process association response.
1353 *
1354 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
1355 * @param mgmt_header Pointer to start of management frame header.
1356 *
1357 * @return EOK if succeed, error code otherwise.
1358 *
1359 */
1360static errno_t ieee80211_process_assoc_response(ieee80211_dev_t *ieee80211_dev,
1361 ieee80211_mgmt_header_t *mgmt_header)
1362{
1363 ieee80211_assoc_resp_body_t *assoc_resp =
1364 (ieee80211_assoc_resp_body_t *) ((void *) mgmt_header +
1365 sizeof(ieee80211_mgmt_header_t));
1366
1367 if (assoc_resp->status != 0)
1368 ieee80211_set_auth_phase(ieee80211_dev,
1369 IEEE80211_AUTH_DISCONNECTED);
1370 else {
1371 ieee80211_dev->bssid_info.aid =
1372 uint16_t_le2host(assoc_resp->aid);
1373 ieee80211_set_auth_phase(ieee80211_dev,
1374 IEEE80211_AUTH_ASSOCIATED);
1375 ieee80211_dev->ops->bssid_change(ieee80211_dev, true);
1376 }
1377
1378 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
1379 fibril_condvar_signal(&ieee80211_dev->gen_cond);
1380 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
1381
1382 return EOK;
1383}
1384
1385static errno_t ieee80211_process_4way_handshake(ieee80211_dev_t *ieee80211_dev,
1386 void *buffer, size_t buffer_size)
1387{
1388 ieee80211_eapol_key_frame_t *key_frame =
1389 (ieee80211_eapol_key_frame_t *) buffer;
1390
1391 ieee80211_scan_result_link_t *auth_link =
1392 ieee80211_dev->bssid_info.res_link;
1393
1394 ieee80211_scan_result_t *auth_data = &auth_link->scan_result;
1395
1396 /* We don't support 802.1X authentication yet. */
1397 if (auth_data->security.auth == IEEE80211_AUTH_AKM_8021X)
1398 return ENOTSUP;
1399
1400 uint8_t *ptk = ieee80211_dev->bssid_info.ptk;
1401 uint8_t *gtk = ieee80211_dev->bssid_info.gtk;
1402 uint8_t gtk_id = 1;
1403
1404 bool handshake_done = false;
1405
1406 bool old_wpa =
1407 auth_data->security.type == IEEE80211_SECURITY_WPA;
1408
1409 bool key_phase =
1410 uint16_t_be2host(key_frame->key_info) &
1411 IEEE80211_EAPOL_KEY_KEYINFO_MIC;
1412
1413 bool final_phase =
1414 uint16_t_be2host(key_frame->key_info) &
1415 IEEE80211_EAPOL_KEY_KEYINFO_SECURE;
1416
1417 bool ccmp_used =
1418 (auth_data->security.pair_alg == IEEE80211_SECURITY_SUITE_CCMP) ||
1419 (auth_data->security.group_alg == IEEE80211_SECURITY_SUITE_CCMP);
1420
1421 size_t ptk_key_length, gtk_key_length;
1422 hash_func_t mic_hash;
1423 if (ccmp_used)
1424 mic_hash = HASH_SHA1;
1425 else
1426 mic_hash = HASH_MD5;
1427
1428 if (auth_data->security.pair_alg == IEEE80211_SECURITY_SUITE_CCMP)
1429 ptk_key_length = IEEE80211_PTK_CCMP_LENGTH;
1430 else
1431 ptk_key_length = IEEE80211_PTK_TKIP_LENGTH;
1432
1433 if (auth_data->security.group_alg == IEEE80211_SECURITY_SUITE_CCMP)
1434 gtk_key_length = IEEE80211_GTK_CCMP_LENGTH;
1435 else
1436 gtk_key_length = IEEE80211_GTK_TKIP_LENGTH;
1437
1438 size_t output_size =
1439 sizeof(eth_header_t) +
1440 sizeof(ieee80211_eapol_key_frame_t);
1441
1442 if (!(uint16_t_be2host(key_frame->key_info) &
1443 IEEE80211_EAPOL_KEY_KEYINFO_MIC))
1444 output_size += auth_link->auth_ie_len;
1445
1446 nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
1447 nic_address_t nic_address;
1448 nic_query_address(nic, &nic_address);
1449
1450 void *output_buffer = malloc(output_size);
1451 if (!output_buffer)
1452 return ENOMEM;
1453
1454 memset(output_buffer, 0, output_size);
1455
1456 /* Setup ethernet header. */
1457 eth_header_t *eth_header = (eth_header_t *) output_buffer;
1458 memcpy(eth_header->dest_addr, auth_data->bssid.address, ETH_ADDR);
1459 memcpy(eth_header->src_addr, nic_address.address, ETH_ADDR);
1460 eth_header->proto = host2uint16_t_be(ETH_TYPE_PAE);
1461
1462 ieee80211_eapol_key_frame_t *output_key_frame =
1463 (ieee80211_eapol_key_frame_t *)
1464 (output_buffer + sizeof(eth_header_t));
1465
1466 /* Copy content of incoming EAPOL-Key frame. */
1467 memcpy((void *) output_key_frame, buffer,
1468 sizeof(ieee80211_eapol_key_frame_t));
1469
1470 output_key_frame->proto_version = 0x1;
1471 output_key_frame->body_length =
1472 host2uint16_t_be(output_size - sizeof(eth_header_t) - 4);
1473 output_key_frame->key_info &=
1474 ~host2uint16_t_be(IEEE80211_EAPOL_KEY_KEYINFO_ACK);
1475
1476 if (key_phase) {
1477 output_key_frame->key_info &=
1478 ~host2uint16_t_be(IEEE80211_EAPOL_KEY_KEYINFO_ENCDATA);
1479 output_key_frame->key_info &=
1480 ~host2uint16_t_be(IEEE80211_EAPOL_KEY_KEYINFO_INSTALL);
1481 output_key_frame->key_data_length = 0;
1482 memset(output_key_frame->key_nonce, 0, 32);
1483 memset(output_key_frame->key_mic, 0, 16);
1484 memset(output_key_frame->key_rsc, 0, 8);
1485 memset(output_key_frame->eapol_key_iv, 0, 16);
1486
1487 /* Derive GTK and save it. */
1488 if (final_phase) {
1489 uint16_t key_data_length =
1490 uint16_t_be2host(key_frame->key_data_length);
1491 uint8_t key_data[key_data_length];
1492 uint8_t *data_ptr = (uint8_t *)
1493 (buffer + sizeof(ieee80211_eapol_key_frame_t));
1494
1495 errno_t rc;
1496 uint8_t work_key[32];
1497
1498 if (ccmp_used) {
1499 rc = ieee80211_aes_key_unwrap(ptk + KEK_OFFSET,
1500 data_ptr, key_data_length, key_data);
1501 } else {
1502 memcpy(work_key, key_frame->eapol_key_iv, 16);
1503 memcpy(work_key + 16, ptk + KEK_OFFSET, 16);
1504 rc = ieee80211_rc4_key_unwrap(work_key,
1505 data_ptr, key_data_length, key_data);
1506 }
1507
1508 if (rc == EOK) {
1509 uint8_t *key_data_ptr = old_wpa ? key_data :
1510 ieee80211_process_ies(ieee80211_dev,
1511 NULL, key_data, key_data_length);
1512
1513 if (key_data_ptr) {
1514 uint8_t *key_ptr;
1515
1516 if (old_wpa)
1517 key_ptr = key_data_ptr;
1518 else {
1519 gtk_id = *key_data_ptr & 0x3;
1520 key_ptr = key_data_ptr + 2;
1521 }
1522
1523 memcpy(gtk, key_ptr, gtk_key_length);
1524 handshake_done = true;
1525 }
1526 }
1527 }
1528 } else {
1529 output_key_frame->key_info |=
1530 host2uint16_t_be(IEEE80211_EAPOL_KEY_KEYINFO_MIC);
1531 output_key_frame->key_data_length =
1532 host2uint16_t_be(auth_link->auth_ie_len);
1533 memcpy((void *) output_key_frame +
1534 sizeof(ieee80211_eapol_key_frame_t),
1535 auth_link->auth_ie, auth_link->auth_ie_len);
1536
1537 /* Compute PMK. */
1538 uint8_t pmk[PBKDF2_KEY_LENGTH];
1539 pbkdf2((uint8_t *) ieee80211_dev->bssid_info.password,
1540 str_size(ieee80211_dev->bssid_info.password),
1541 (uint8_t *) auth_data->ssid,
1542 str_size(auth_data->ssid), pmk);
1543
1544 uint8_t *anonce = key_frame->key_nonce;
1545
1546 /* Generate SNONCE. */
1547 uint8_t snonce[32];
1548 rnd_sequence(snonce, 32);
1549
1550 memcpy(output_key_frame->key_nonce, snonce, 32);
1551
1552 uint8_t *dest_addr = eth_header->dest_addr;
1553 uint8_t *src_addr = eth_header->src_addr;
1554
1555 /* Derive PTK and save it. */
1556 uint8_t crypt_data[PRF_CRYPT_DATA_LENGTH];
1557 memcpy(crypt_data,
1558 min_sequence(dest_addr, src_addr, ETH_ADDR), ETH_ADDR);
1559 memcpy(crypt_data + ETH_ADDR,
1560 max_sequence(dest_addr, src_addr, ETH_ADDR), ETH_ADDR);
1561 memcpy(crypt_data + 2 * ETH_ADDR,
1562 min_sequence(anonce, snonce, 32), 32);
1563 memcpy(crypt_data + 2 * ETH_ADDR + 32,
1564 max_sequence(anonce, snonce, 32), 32);
1565 ieee80211_prf(pmk, crypt_data, ptk, ptk_key_length);
1566 }
1567
1568 /* Compute MIC of key frame data from KCK part of PTK. */
1569 uint8_t mic[mic_hash];
1570 hmac(ptk, 16, (uint8_t *) output_key_frame,
1571 output_size - sizeof(eth_header_t), mic, mic_hash);
1572
1573 memcpy(output_key_frame->key_mic, mic, 16);
1574
1575 ieee80211_send_frame(nic, output_buffer, output_size);
1576
1577 free(output_buffer);
1578
1579 ieee80211_key_config_t key_config;
1580
1581 /* Insert Pairwise key. */
1582 if ((key_phase && old_wpa) || (final_phase && !old_wpa)) {
1583 key_config.suite = auth_data->security.pair_alg;
1584 key_config.flags =
1585 IEEE80211_KEY_FLAG_TYPE_PAIRWISE;
1586 memcpy(key_config.data,
1587 ptk + TK_OFFSET, ptk_key_length - TK_OFFSET);
1588
1589 ieee80211_dev->ops->key_config(ieee80211_dev,
1590 &key_config, true);
1591 }
1592
1593 /* Insert Group key. */
1594 if (final_phase) {
1595 key_config.id = gtk_id;
1596 key_config.suite = auth_data->security.group_alg;
1597 key_config.flags = IEEE80211_KEY_FLAG_TYPE_GROUP;
1598 memcpy(key_config.data, gtk, gtk_key_length);
1599
1600 ieee80211_dev->ops->key_config(ieee80211_dev,
1601 &key_config, true);
1602 }
1603
1604 /* Signal successful handshake completion. */
1605 if (handshake_done) {
1606 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
1607 fibril_condvar_signal(&ieee80211_dev->gen_cond);
1608 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
1609 }
1610
1611 return EOK;
1612}
1613
1614static errno_t ieee80211_process_eapol_frame(ieee80211_dev_t *ieee80211_dev,
1615 void *buffer, size_t buffer_size)
1616{
1617 ieee80211_eapol_key_frame_t *key_frame =
1618 (ieee80211_eapol_key_frame_t *) buffer;
1619
1620 if (ieee80211_is_eapol_key_frame(key_frame))
1621 return ieee80211_process_4way_handshake(ieee80211_dev, buffer,
1622 buffer_size);
1623
1624 return EOK;
1625}
1626
1627/** Process data frame.
1628 *
1629 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
1630 * @param buffer Data buffer starting with IEEE 802.11 data header.
1631 * @param buffer_size Size of buffer.
1632 *
1633 * @return EOK if succeed, error code otherwise.
1634 *
1635 */
1636static errno_t ieee80211_process_data(ieee80211_dev_t *ieee80211_dev,
1637 void *buffer, size_t buffer_size)
1638{
1639 ieee80211_data_header_t *data_header =
1640 (ieee80211_data_header_t *) buffer;
1641
1642 if (ieee80211_has_data_frame(data_header->frame_ctrl)) {
1643 nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
1644 size_t strip_length = sizeof(ieee80211_data_header_t) +
1645 ARRAY_SIZE(rfc1042_header);
1646
1647 /* TODO: Different by used security alg. */
1648 /* TODO: Trim frame by used security alg. */
1649 // TODO: Distinguish used key (pair/group) by dest address ?
1650 if (ieee80211_is_encrypted_frame(data_header->frame_ctrl))
1651 strip_length += 8;
1652
1653 /* Process 4-way authentication handshake. */
1654 uint16_t *proto = (uint16_t *) (buffer + strip_length);
1655 if (uint16_t_be2host(*proto) == ETH_TYPE_PAE)
1656 return ieee80211_process_eapol_frame(ieee80211_dev,
1657 buffer + strip_length + sizeof(uint16_t),
1658 buffer_size - strip_length - sizeof(uint16_t));
1659
1660 /*
1661 * Note: ETH protocol ID is already there, so we don't create
1662 * whole ETH header.
1663 */
1664 size_t frame_size =
1665 buffer_size - strip_length + sizeof(eth_header_t) - 2;
1666 nic_frame_t *frame = nic_alloc_frame(nic, frame_size);
1667
1668 if (frame == NULL)
1669 return ENOMEM;
1670
1671 uint8_t *src_addr =
1672 ieee80211_is_fromds_frame(data_header->frame_ctrl) ?
1673 data_header->address3 : data_header->address2;
1674 uint8_t *dest_addr =
1675 ieee80211_is_tods_frame(data_header->frame_ctrl) ?
1676 data_header->address3 : data_header->address1;
1677
1678 eth_header_t *eth_header = (eth_header_t *) frame->data;
1679 memcpy(eth_header->src_addr, src_addr, ETH_ADDR);
1680 memcpy(eth_header->dest_addr, dest_addr, ETH_ADDR);
1681
1682 memcpy(frame->data + sizeof(eth_header_t) - 2,
1683 buffer + strip_length, buffer_size - strip_length);
1684
1685 nic_received_frame(nic, frame);
1686 }
1687
1688 return EOK;
1689}
1690
1691/** IEEE 802.11 RX frames handler.
1692 *
1693 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
1694 * @param buffer Buffer with data.
1695 * @param buffer_size Size of buffer.
1696 *
1697 * @return EOK if succeed, error code otherwise.
1698 *
1699 */
1700errno_t ieee80211_rx_handler(ieee80211_dev_t *ieee80211_dev, void *buffer,
1701 size_t buffer_size)
1702{
1703 uint16_t frame_ctrl = *((uint16_t *) buffer);
1704
1705 if (ieee80211_is_mgmt_frame(frame_ctrl)) {
1706 ieee80211_mgmt_header_t *mgmt_header =
1707 (ieee80211_mgmt_header_t *) buffer;
1708
1709 if ((ieee80211_is_probe_response_frame(mgmt_header->frame_ctrl)) ||
1710 (ieee80211_is_beacon_frame(mgmt_header->frame_ctrl)))
1711 return ieee80211_process_probe_response(ieee80211_dev,
1712 mgmt_header, buffer_size);
1713
1714 if (ieee80211_is_auth_frame(mgmt_header->frame_ctrl))
1715 return ieee80211_process_auth_response(ieee80211_dev,
1716 mgmt_header);
1717
1718 if (ieee80211_is_assoc_response_frame(mgmt_header->frame_ctrl))
1719 return ieee80211_process_assoc_response(ieee80211_dev,
1720 mgmt_header);
1721 } else if (ieee80211_is_data_frame(frame_ctrl))
1722 return ieee80211_process_data(ieee80211_dev, buffer,
1723 buffer_size);
1724
1725 return EOK;
1726}
1727
1728/** @}
1729 */
Note: See TracBrowser for help on using the repository browser.