source: mainline/uspace/lib/ieee80211/src/ieee80211.c@ 1dcc0b9

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1dcc0b9 was 1dcc0b9, checked in by Jan Kolarik <kolarik@…>, 10 years ago

Scanning whole 2.4GHz spectrum, created supplicant for managing connection between device STA and AP, finished association process between STA and AP, handling 4way handshake protocol used for key management, written needed cryptographic algorithms (AES, SHA1, HMAC, PBKDF2) for CCMP protocol, data communication on OPEN/CCMP networks.

  • Property mode set to 100644
File size: 42.4 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
44#include <ieee80211.h>
45#include <ieee80211_impl.h>
46#include <ieee80211_iface_impl.h>
47#include <ieee80211_private.h>
48#include <ops/ieee80211.h>
49
50#define IEEE80211_DATA_RATES_SIZE 8
51#define IEEE80211_EXT_DATA_RATES_SIZE 4
52
53/** Frame encapsulation used in IEEE 802.11. */
54static const uint8_t rfc1042_header[] = {
55 0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00
56};
57
58/** Broadcast MAC address used to spread probe request through channel. */
59static const uint8_t ieee80211_broadcast_mac_addr[] = {
60 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
61};
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 */
70inline bool ieee80211_is_data_frame(uint16_t frame_ctrl)
71{
72 frame_ctrl = uint16_t_le2host(frame_ctrl);
73
74 return (frame_ctrl & IEEE80211_FRAME_CTRL_FRAME_TYPE)
75 == IEEE80211_DATA_FRAME;
76}
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 */
85inline bool ieee80211_is_mgmt_frame(uint16_t frame_ctrl)
86{
87 frame_ctrl = uint16_t_le2host(frame_ctrl);
88
89 return (frame_ctrl & IEEE80211_FRAME_CTRL_FRAME_TYPE)
90 == IEEE80211_MGMT_FRAME;
91}
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 */
100inline bool ieee80211_is_beacon_frame(uint16_t frame_ctrl)
101{
102 frame_ctrl = uint16_t_le2host(frame_ctrl);
103
104 return (frame_ctrl & IEEE80211_FRAME_CTRL_FRAME_SUBTYPE)
105 == IEEE80211_MGMT_BEACON_FRAME;
106}
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 */
115inline bool ieee80211_is_probe_response_frame(uint16_t frame_ctrl)
116{
117 frame_ctrl = uint16_t_le2host(frame_ctrl);
118
119 return (frame_ctrl & IEEE80211_FRAME_CTRL_FRAME_SUBTYPE)
120 == IEEE80211_MGMT_PROBE_RESP_FRAME;
121}
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 */
130inline bool ieee80211_is_auth_frame(uint16_t frame_ctrl)
131{
132 frame_ctrl = uint16_t_le2host(frame_ctrl);
133
134 return (frame_ctrl & IEEE80211_FRAME_CTRL_FRAME_SUBTYPE)
135 == IEEE80211_MGMT_AUTH_FRAME;
136}
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 */
145inline bool ieee80211_is_assoc_response_frame(uint16_t frame_ctrl)
146{
147 frame_ctrl = uint16_t_le2host(frame_ctrl);
148
149 return (frame_ctrl & IEEE80211_FRAME_CTRL_FRAME_SUBTYPE)
150 == IEEE80211_MGMT_ASSOC_RESP_FRAME;
151}
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 */
160static inline bool ieee80211_is_tods_frame(uint16_t frame_ctrl)
161{
162 frame_ctrl = uint16_t_le2host(frame_ctrl);
163
164 return (frame_ctrl & IEEE80211_FRAME_CTRL_TODS);
165}
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 */
174static inline bool ieee80211_is_fromds_frame(uint16_t frame_ctrl)
175{
176 frame_ctrl = uint16_t_le2host(frame_ctrl);
177
178 return (frame_ctrl & IEEE80211_FRAME_CTRL_FROMDS);
179}
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 */
188static inline bool ieee80211_has_data_frame(uint16_t frame_ctrl)
189{
190 frame_ctrl = uint16_t_le2host(frame_ctrl);
191
192 return (frame_ctrl & (IEEE80211_FRAME_CTRL_FRAME_TYPE | 0x40))
193 == IEEE80211_DATA_FRAME;
194}
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 */
203static inline bool ieee80211_is_encrypted_frame(uint16_t frame_ctrl)
204{
205 frame_ctrl = uint16_t_le2host(frame_ctrl);
206
207 return (frame_ctrl & IEEE80211_FRAME_CTRL_PROTECTED) != 0;
208}
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 */
217static inline bool ieee80211_is_eapol_key_frame(ieee80211_eapol_key_frame_t
218 *key_frame)
219{
220 return (key_frame->packet_type == IEEE80211_EAPOL_KEY);
221}
222
223
224/**
225 * Generate packet sequence number.
226 *
227 * @param ieee80211_dev IEEE 802.11 device.
228 *
229 * @return True if it has payload data, otherwise false.
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 return ret_val;
236}
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 */
245void *ieee80211_get_specific(ieee80211_dev_t* ieee80211_dev)
246{
247 return ieee80211_dev->specific;
248}
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 */
256void ieee80211_set_specific(ieee80211_dev_t* ieee80211_dev,
257 void *specific)
258{
259 ieee80211_dev->specific = specific;
260}
261
262/**
263 * Get related DDF device.
264 *
265 * @param ieee80211_dev IEEE 802.11 device.
266 *
267 * @return DDF device.
268 */
269ddf_dev_t *ieee80211_get_ddf_dev(ieee80211_dev_t* ieee80211_dev)
270{
271 return ieee80211_dev->ddf_dev;
272}
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 */
281ieee80211_operating_mode_t ieee80211_query_current_op_mode(ieee80211_dev_t*
282 ieee80211_dev)
283{
284 return ieee80211_dev->current_op_mode;
285}
286
287/**
288 * Query current frequency of IEEE 802.11 device.
289 *
290 * @param ieee80211_dev IEEE 802.11 device.
291 *
292 * @return Current device operating frequency.
293 */
294uint16_t ieee80211_query_current_freq(ieee80211_dev_t* ieee80211_dev)
295{
296 return ieee80211_dev->current_freq;
297}
298
299/**
300 * Query BSSID the device is connected to.
301 *
302 * @param ieee80211_dev IEEE 802.11 device.
303 * @param bssid Pointer to structure where should be stored BSSID.
304 */
305void ieee80211_query_bssid(ieee80211_dev_t* ieee80211_dev,
306 nic_address_t *bssid)
307{
308 if(bssid) {
309 ieee80211_scan_result_t *auth_data =
310 &ieee80211_dev->bssid_info.res_link->scan_result;
311
312 memcpy(bssid, (void *)&auth_data->bssid, sizeof(nic_address_t));
313 }
314}
315
316/**
317 * Get AID of network we are connected to.
318 *
319 * @param ieee80211_dev IEEE 802.11 device.
320 *
321 * @return AID.
322 */
323uint16_t ieee80211_get_aid(ieee80211_dev_t* ieee80211_dev)
324{
325 return ieee80211_dev->bssid_info.aid;
326}
327
328/**
329 * Get security suite used for HW encryption.
330 *
331 * @param ieee80211_dev IEEE 802.11 device.
332 *
333 * @return Security suite indicator.
334 */
335int ieee80211_get_security_suite(ieee80211_dev_t* ieee80211_dev)
336{
337 ieee80211_scan_result_link_t *auth_link =
338 ieee80211_dev->bssid_info.res_link;
339
340 return auth_link->scan_result.security.pair_alg;
341}
342
343/**
344 * Check if IEEE 802.11 device is connected to network.
345 *
346 * @param ieee80211_dev IEEE 802.11 device.
347 *
348 * @return True if device is connected to network, otherwise false.
349 */
350bool ieee80211_is_connected(ieee80211_dev_t* ieee80211_dev)
351{
352 return ieee80211_dev->current_auth_phase == IEEE80211_AUTH_ASSOCIATED;
353}
354
355/**
356 * Report current operating mode for IEEE 802.11 device.
357 *
358 * @param ieee80211_dev IEEE 802.11 device.
359 * @param op_mode Current IEEE 802.11 operating mode.
360 */
361void ieee80211_report_current_op_mode(ieee80211_dev_t* ieee80211_dev,
362 ieee80211_operating_mode_t op_mode)
363{
364 ieee80211_dev->current_op_mode = op_mode;
365}
366
367/**
368 * Report current frequency for IEEE 802.11 device.
369 *
370 * @param ieee80211_dev IEEE 802.11 device.
371 * @param freq Current device operating frequency.
372 */
373void ieee80211_report_current_freq(ieee80211_dev_t* ieee80211_dev,
374 uint16_t freq)
375{
376 ieee80211_dev->current_freq = freq;
377}
378
379/**
380 * Check if IEEE 802.11 device is ready (fully initialized).
381 *
382 * @param ieee80211_dev IEEE 802.11 device.
383 *
384 * @return True if device is ready to work, otherwise false.
385 */
386bool ieee80211_is_ready(ieee80211_dev_t* ieee80211_dev)
387{
388 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
389 bool ready_state = ieee80211_dev->ready;
390 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
391
392 return ready_state;
393}
394
395/**
396 * Set IEEE 802.11 device to ready state.
397 *
398 * @param ieee80211_dev IEEE 802.11 device.
399 * @param ready Ready state to be set.
400 */
401void ieee80211_set_ready(ieee80211_dev_t* ieee80211_dev, bool ready)
402{
403 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
404 ieee80211_dev->ready = ready;
405 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
406}
407
408extern bool ieee80211_query_using_key(ieee80211_dev_t* ieee80211_dev)
409{
410 return ieee80211_dev->using_hw_key;
411}
412
413void ieee80211_setup_key_confirm(ieee80211_dev_t* ieee80211_dev,
414 bool using_key)
415{
416 ieee80211_dev->using_hw_key = using_key;
417}
418
419/**
420 * Implementation of NIC open callback for IEEE 802.11 devices.
421 *
422 * @param fun NIC function.
423 *
424 * @return EOK if succeed, negative error code otherwise.
425 */
426static int ieee80211_open(ddf_fun_t *fun)
427{
428 nic_t *nic_data = nic_get_from_ddf_fun(fun);
429 ieee80211_dev_t *ieee80211_dev = nic_get_specific(nic_data);
430
431 if(ieee80211_dev->started) {
432 return EOK;
433 } else {
434 ieee80211_dev->started = true;
435 }
436
437 int rc = ieee80211_dev->ops->start(ieee80211_dev);
438 if(rc != EOK)
439 return rc;
440
441 rc = ieee80211_dev->ops->scan(ieee80211_dev);
442 if(rc != EOK)
443 return rc;
444
445 return EOK;
446}
447
448/**
449 * Send frame handler.
450 *
451 * @param nic Pointer to NIC device.
452 * @param data Data buffer.
453 * @param size Data buffer size.
454 */
455static void ieee80211_send_frame(nic_t *nic, void *data, size_t size)
456{
457 ieee80211_dev_t *ieee80211_dev = (ieee80211_dev_t *)
458 nic_get_specific(nic);
459
460 if(!ieee80211_is_connected(ieee80211_dev)) {
461 return;
462 }
463
464 ieee80211_scan_result_t *auth_data =
465 &ieee80211_dev->bssid_info.res_link->scan_result;
466
467 /* We drop part of IEEE 802.3 ethernet header. */
468 size_t drop_bytes = sizeof(eth_header_t) - 2;
469
470 size_t complete_size = (size - drop_bytes) +
471 sizeof(ieee80211_data_header_t) +
472 ARRAY_SIZE(rfc1042_header);
473
474 /* Init crypto data. */
475 size_t add_size = 0;
476 uint16_t crypto = 0;
477 uint8_t add_data[8];
478 memset(add_data, 0, 8);
479
480 if(ieee80211_dev->using_hw_key) {
481 int sec_suite = auth_data->security.pair_alg;
482 switch(sec_suite) {
483 case IEEE80211_SECURITY_SUITE_CCMP:
484 add_size = IEEE80211_CCMP_HEADER_LENGTH;
485 add_data[3] = 0x20;
486 break;
487 default:
488 break;
489 }
490
491 crypto = uint16_t_le2host(IEEE80211_FRAME_CTRL_PROTECTED);
492 }
493
494 complete_size += add_size;
495
496 void *complete_buffer = malloc(complete_size);
497 memset(complete_buffer, 0, complete_size);
498
499 if(add_size) {
500 memcpy(complete_buffer + sizeof(ieee80211_data_header_t),
501 add_data, add_size);
502 }
503
504 memcpy(complete_buffer + sizeof(ieee80211_data_header_t) + add_size,
505 rfc1042_header,
506 ARRAY_SIZE(rfc1042_header));
507
508 memcpy(complete_buffer +
509 sizeof(ieee80211_data_header_t) +
510 ARRAY_SIZE(rfc1042_header) + add_size,
511 data + drop_bytes, size - drop_bytes);
512
513 ieee80211_data_header_t *data_header =
514 (ieee80211_data_header_t *) complete_buffer;
515 data_header->frame_ctrl =
516 uint16_t_le2host(IEEE80211_DATA_FRAME) |
517 uint16_t_le2host(IEEE80211_DATA_DATA_FRAME) |
518 uint16_t_le2host(IEEE80211_FRAME_CTRL_TODS) |
519 crypto;
520 data_header->seq_ctrl = ieee80211_get_sequence_number(ieee80211_dev);
521
522 /* BSSID, SA, DA. */
523 memcpy(data_header->address1, auth_data->bssid.address, ETH_ADDR);
524 memcpy(data_header->address2, data + ETH_ADDR, ETH_ADDR);
525 memcpy(data_header->address3, data, ETH_ADDR);
526
527 ieee80211_dev->ops->tx_handler(ieee80211_dev,
528 complete_buffer,
529 complete_size);
530
531 free(complete_buffer);
532}
533
534/**
535 * Fill out IEEE 802.11 device functions implementations.
536 *
537 * @param ieee80211_dev IEEE 802.11 device.
538 * @param ieee80211_ops Callbacks implementation.
539 * @param ieee80211_iface Interface functions implementation.
540 * @param nic_iface NIC interface functions implementation.
541 * @param nic_dev_ops NIC device functions implementation.
542 *
543 * @return EINVAL when missing pointer to ieee80211_ops or ieee80211_iface,
544 * otherwise EOK.
545 */
546static int ieee80211_implement(ieee80211_dev_t *ieee80211_dev,
547 ieee80211_ops_t *ieee80211_ops, ieee80211_iface_t *ieee80211_iface,
548 nic_iface_t *nic_iface, ddf_dev_ops_t *nic_dev_ops)
549{
550 if(ieee80211_ops) {
551 if(!ieee80211_ops->start)
552 ieee80211_ops->start = ieee80211_start_impl;
553
554 if(!ieee80211_ops->tx_handler)
555 ieee80211_ops->tx_handler = ieee80211_tx_handler_impl;
556
557 if(!ieee80211_ops->set_freq)
558 ieee80211_ops->set_freq = ieee80211_set_freq_impl;
559
560 if(!ieee80211_ops->bssid_change)
561 ieee80211_ops->bssid_change =
562 ieee80211_bssid_change_impl;
563
564 if(!ieee80211_ops->key_config)
565 ieee80211_ops->key_config = ieee80211_key_config_impl;
566
567 if(!ieee80211_ops->scan)
568 ieee80211_ops->scan = ieee80211_scan_impl;
569 } else {
570 return EINVAL;
571 }
572
573 ieee80211_dev->ops = ieee80211_ops;
574
575 if(ieee80211_iface) {
576 if(nic_dev_ops)
577 if (!nic_dev_ops->interfaces[IEEE80211_DEV_IFACE])
578 nic_dev_ops->interfaces[IEEE80211_DEV_IFACE] =
579 ieee80211_iface;
580
581 if(!ieee80211_iface->get_scan_results)
582 ieee80211_iface->get_scan_results =
583 ieee80211_get_scan_results_impl;
584
585 if(!ieee80211_iface->connect)
586 ieee80211_iface->connect = ieee80211_connect_impl;
587
588 if(!ieee80211_iface->disconnect)
589 ieee80211_iface->disconnect = ieee80211_disconnect_impl;
590 } else {
591 return EINVAL;
592 }
593
594 if(nic_dev_ops) {
595 if(!nic_dev_ops->open)
596 nic_dev_ops->open = ieee80211_open;
597 } else {
598 return EINVAL;
599 }
600
601 ieee80211_dev->iface = ieee80211_iface;
602
603 nic_driver_implement(NULL, nic_dev_ops, nic_iface);
604
605 return EOK;
606}
607
608/**
609 * Allocate IEEE802.11 device structure.
610 *
611 * @return Pointer to allocated IEEE802.11 device structure.
612 */
613ieee80211_dev_t *ieee80211_device_create()
614{
615 return calloc(1, sizeof(ieee80211_dev_t));
616}
617
618/**
619 * Initialize an IEEE802.11 framework structure.
620 *
621 * @param ieee80211_dev Device structure to initialize.
622 * @param ddf_dev Pointer to backing DDF device structure.
623 *
624 * @return EOK if succeed, negative error code otherwise.
625 */
626int ieee80211_device_init(ieee80211_dev_t *ieee80211_dev, ddf_dev_t *ddf_dev)
627{
628 ieee80211_dev->ddf_dev = ddf_dev;
629 ieee80211_dev->started = false;
630 ieee80211_dev->ready = false;
631 ieee80211_dev->using_hw_key = false;
632 ieee80211_dev->current_op_mode = IEEE80211_OPMODE_STATION;
633 ieee80211_dev->current_auth_phase = IEEE80211_AUTH_DISCONNECTED;
634 memcpy(ieee80211_dev->bssid_mask.address, ieee80211_broadcast_mac_addr,
635 ETH_ADDR);
636
637 ieee80211_scan_result_list_init(&ieee80211_dev->ap_list);
638
639 fibril_mutex_initialize(&ieee80211_dev->gen_mutex);
640 fibril_condvar_initialize(&ieee80211_dev->gen_cond);
641
642 /* Bind NIC to device */
643 nic_t *nic = nic_create_and_bind(ddf_dev);
644 if (!nic) {
645 return ENOMEM;
646 }
647
648 nic_set_specific(nic, ieee80211_dev);
649
650 return EOK;
651}
652
653/**
654 * IEEE802.11 WiFi framework initialization.
655 *
656 * @param ieee80211_dev Device structure to initialize.
657 * @param ieee80211_ops Structure with implemented IEEE802.11 device operations.
658 * @param ieee80211_iface Structure with implemented IEEE802.11 interface
659 * operations.
660 *
661 * @return EOK if succeed, negative error code otherwise.
662 */
663int ieee80211_init(ieee80211_dev_t *ieee80211_dev,
664 ieee80211_ops_t *ieee80211_ops, ieee80211_iface_t *ieee80211_iface,
665 nic_iface_t *ieee80211_nic_iface, ddf_dev_ops_t *ieee80211_nic_dev_ops)
666{
667 int rc = ieee80211_implement(ieee80211_dev,
668 ieee80211_ops, ieee80211_iface,
669 ieee80211_nic_iface, ieee80211_nic_dev_ops);
670 if(rc != EOK) {
671 return rc;
672 }
673
674 nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
675
676 /** TODO: Set NIC handlers here. */
677 nic_set_send_frame_handler(nic, ieee80211_send_frame);
678
679 ddf_fun_t *fun = ddf_fun_create(ieee80211_dev->ddf_dev, fun_exposed,
680 "port0");
681 if (fun == NULL) {
682 return EINVAL;
683 }
684
685 nic_set_ddf_fun(nic, fun);
686 ddf_fun_set_ops(fun, ieee80211_nic_dev_ops);
687
688 rc = ddf_fun_bind(fun);
689 if (rc != EOK) {
690 ddf_fun_destroy(fun);
691 return rc;
692 }
693 rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC);
694 if (rc != EOK) {
695 ddf_fun_unbind(fun);
696 return rc;
697 }
698 rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_IEEE80211);
699 if (rc != EOK) {
700 ddf_fun_unbind(fun);
701 return rc;
702 }
703
704 return EOK;
705}
706
707/**
708 * Convert frequency value to channel number.
709 *
710 * @param freq IEEE 802.11 operating frequency.
711 *
712 * @return Operating channel number.
713 */
714static uint8_t ieee80211_freq_to_channel(uint16_t freq)
715{
716 return (freq - IEEE80211_FIRST_FREQ) / IEEE80211_CHANNEL_GAP + 1;
717}
718
719static void ieee80211_prepare_ie_header(void **ie_header,
720 uint8_t id, uint8_t length, void *data)
721{
722 ieee80211_ie_header_t *header =
723 (ieee80211_ie_header_t *) *ie_header;
724
725 header->element_id = id;
726 header->length = length;
727
728 memcpy(*ie_header + sizeof(ieee80211_ie_header_t), data, length);
729
730 *ie_header = (void *) ((void *) header +
731 sizeof(ieee80211_ie_header_t) + length);
732}
733
734/**
735 * Probe request implementation.
736 *
737 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
738 * @param ssid Probing SSID or NULL if broadcast.
739 *
740 * @return EOK if succeed, negative error code otherwise.
741 */
742int ieee80211_probe_request(ieee80211_dev_t *ieee80211_dev, char *ssid)
743{
744 nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
745 nic_address_t nic_address;
746 nic_query_address(nic, &nic_address);
747
748 size_t ssid_data_size = (ssid != NULL) ? str_size(ssid) : 0;
749 size_t channel_data_size = 1;
750
751 uint8_t channel =
752 ieee80211_freq_to_channel(ieee80211_dev->current_freq);
753
754 /* 4 headers - (ssid, rates, ext rates, current channel) and their data
755 * lengths.
756 */
757 size_t payload_size =
758 sizeof(ieee80211_ie_header_t) * 4 +
759 ssid_data_size +
760 IEEE80211_DATA_RATES_SIZE + IEEE80211_EXT_DATA_RATES_SIZE +
761 channel_data_size;
762
763 size_t buffer_size = sizeof(ieee80211_mgmt_header_t) + payload_size;
764 void *buffer = malloc(buffer_size);
765 memset(buffer, 0, buffer_size);
766
767 ieee80211_mgmt_header_t *mgmt_header =
768 (ieee80211_mgmt_header_t *) buffer;
769
770 mgmt_header->frame_ctrl = host2uint16_t_le(
771 IEEE80211_MGMT_FRAME |
772 IEEE80211_MGMT_PROBE_REQ_FRAME
773 );
774 memcpy(mgmt_header->dest_addr, ieee80211_broadcast_mac_addr, ETH_ADDR);
775 memcpy(mgmt_header->src_addr, nic_address.address, ETH_ADDR);
776 memcpy(mgmt_header->bssid, ieee80211_broadcast_mac_addr, ETH_ADDR);
777 mgmt_header->seq_ctrl =
778 host2uint16_t_le(ieee80211_get_sequence_number(ieee80211_dev));
779
780 /* Jump to payload. */
781 void *it = (void *) buffer + sizeof(ieee80211_mgmt_header_t);
782 ieee80211_prepare_ie_header(&it, IEEE80211_SSID_IE, ssid_data_size,
783 (void *) ssid);
784 ieee80211_prepare_ie_header(&it, IEEE80211_RATES_IE,
785 IEEE80211_DATA_RATES_SIZE,
786 (void *) &ieee80211bg_data_rates);
787 ieee80211_prepare_ie_header(&it, IEEE80211_EXT_RATES_IE,
788 IEEE80211_EXT_DATA_RATES_SIZE,
789 (void *) &ieee80211bg_data_rates[IEEE80211_DATA_RATES_SIZE]);
790 ieee80211_prepare_ie_header(&it, IEEE80211_CHANNEL_IE,
791 channel_data_size, (void *) &channel);
792
793 ieee80211_dev->ops->tx_handler(ieee80211_dev, buffer, buffer_size);
794
795 free(buffer);
796
797 return EOK;
798}
799
800/**
801 * IEEE 802.11 authentication implementation.
802 *
803 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
804 *
805 * @return EOK if succeed, negative error code otherwise.
806 */
807int ieee80211_authenticate(ieee80211_dev_t *ieee80211_dev)
808{
809 nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
810 nic_address_t nic_address;
811 nic_query_address(nic, &nic_address);
812
813 ieee80211_scan_result_t *auth_data =
814 &ieee80211_dev->bssid_info.res_link->scan_result;
815
816 size_t buffer_size = sizeof(ieee80211_mgmt_header_t) +
817 sizeof(ieee80211_auth_body_t);
818
819 void *buffer = malloc(buffer_size);
820 memset(buffer, 0, buffer_size);
821
822 ieee80211_mgmt_header_t *mgmt_header =
823 (ieee80211_mgmt_header_t *) buffer;
824
825 mgmt_header->frame_ctrl = host2uint16_t_le(
826 IEEE80211_MGMT_FRAME |
827 IEEE80211_MGMT_AUTH_FRAME
828 );
829 memcpy(mgmt_header->dest_addr, auth_data->bssid.address, ETH_ADDR);
830 memcpy(mgmt_header->src_addr, nic_address.address, ETH_ADDR);
831 memcpy(mgmt_header->bssid, auth_data->bssid.address, ETH_ADDR);
832
833 ieee80211_auth_body_t *auth_body =
834 (ieee80211_auth_body_t *)
835 (buffer + sizeof(ieee80211_mgmt_header_t));
836 auth_body->auth_alg = host2uint16_t_le(0);
837 auth_body->auth_trans_no = host2uint16_t_le(1);
838
839 ieee80211_dev->ops->tx_handler(ieee80211_dev, buffer, buffer_size);
840
841 free(buffer);
842
843 return EOK;
844}
845
846/**
847 * IEEE 802.11 association implementation.
848 *
849 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
850 * @param password Passphrase to be used in encrypted communication or NULL
851 * for open networks.
852 *
853 * @return EOK if succeed, negative error code otherwise.
854 */
855int ieee80211_associate(ieee80211_dev_t *ieee80211_dev, char *password)
856{
857 nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
858 nic_address_t nic_address;
859 nic_query_address(nic, &nic_address);
860
861 ieee80211_scan_result_link_t *auth_link =
862 ieee80211_dev->bssid_info.res_link;
863
864 ieee80211_scan_result_t *auth_data = &auth_link->scan_result;
865
866 size_t ssid_data_size = str_size(auth_data->ssid);
867
868 size_t payload_size =
869 sizeof(ieee80211_ie_header_t) * 3 +
870 ssid_data_size +
871 IEEE80211_DATA_RATES_SIZE +
872 IEEE80211_EXT_DATA_RATES_SIZE;
873
874 size_t buffer_size =
875 sizeof(ieee80211_mgmt_header_t) +
876 sizeof(ieee80211_assoc_req_body_t) +
877 payload_size;
878
879 if(auth_data->security.type == IEEE80211_SECURITY_WPA2) {
880 buffer_size += auth_link->rsn_copy_len;
881 }
882
883 void *buffer = malloc(buffer_size);
884 memset(buffer, 0, buffer_size);
885
886 ieee80211_mgmt_header_t *mgmt_header =
887 (ieee80211_mgmt_header_t *) buffer;
888
889 mgmt_header->frame_ctrl = host2uint16_t_le(
890 IEEE80211_MGMT_FRAME |
891 IEEE80211_MGMT_ASSOC_REQ_FRAME
892 );
893 memcpy(mgmt_header->dest_addr, auth_data->bssid.address, ETH_ADDR);
894 memcpy(mgmt_header->src_addr, nic_address.address, ETH_ADDR);
895 memcpy(mgmt_header->bssid, auth_data->bssid.address, ETH_ADDR);
896
897 ieee80211_assoc_req_body_t *assoc_body =
898 (ieee80211_assoc_req_body_t *)
899 (buffer + sizeof(ieee80211_mgmt_header_t));
900 assoc_body->listen_interval = host2uint16_t_le(1);
901
902 /* Jump to payload. */
903 void *it = buffer + sizeof(ieee80211_mgmt_header_t) +
904 sizeof(ieee80211_assoc_req_body_t);
905 ieee80211_prepare_ie_header(&it, IEEE80211_SSID_IE,
906 ssid_data_size, (void *) auth_data->ssid);
907 ieee80211_prepare_ie_header(&it, IEEE80211_RATES_IE,
908 IEEE80211_DATA_RATES_SIZE,
909 (void *) &ieee80211bg_data_rates);
910 ieee80211_prepare_ie_header(&it, IEEE80211_EXT_RATES_IE,
911 IEEE80211_EXT_DATA_RATES_SIZE,
912 (void *) &ieee80211bg_data_rates[IEEE80211_DATA_RATES_SIZE]);
913
914 if(auth_data->security.type != IEEE80211_SECURITY_OPEN) {
915 assoc_body->capability |= host2uint16_t_le(CAP_SECURITY);
916 }
917
918 if(auth_data->security.type == IEEE80211_SECURITY_WPA2) {
919 memcpy(it, auth_link->rsn_copy, auth_link->rsn_copy_len);
920 }
921
922 ieee80211_dev->ops->tx_handler(ieee80211_dev, buffer, buffer_size);
923
924 /*
925 * Save password and SSID to be used in eventual authentication
926 * handshake.
927 */
928 memcpy(ieee80211_dev->bssid_info.password, password,
929 str_size(password));
930
931 free(buffer);
932
933 return EOK;
934}
935
936/**
937 * IEEE 802.11 deauthentication implementation.
938 *
939 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
940 *
941 * @return EOK if succeed, negative error code otherwise.
942 */
943int ieee80211_deauthenticate(ieee80211_dev_t *ieee80211_dev)
944{
945 ieee80211_scan_result_t *auth_data =
946 &ieee80211_dev->bssid_info.res_link->scan_result;
947
948 ieee80211_dev->current_auth_phase = IEEE80211_AUTH_DISCONNECTED;
949 ieee80211_dev->bssid_info.aid = (uint16_t) -1;
950 memcpy(auth_data->bssid.address, ieee80211_broadcast_mac_addr,
951 ETH_ADDR);
952
953 nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
954 nic_address_t nic_address;
955 nic_query_address(nic, &nic_address);
956
957 size_t buffer_size = sizeof(ieee80211_mgmt_header_t) +
958 sizeof(ieee80211_deauth_body_t);
959 void *buffer = malloc(buffer_size);
960 memset(buffer, 0, buffer_size);
961
962 ieee80211_mgmt_header_t *mgmt_header =
963 (ieee80211_mgmt_header_t *) buffer;
964
965 mgmt_header->frame_ctrl = host2uint16_t_le(
966 IEEE80211_MGMT_FRAME |
967 IEEE80211_MGMT_DEAUTH_FRAME
968 );
969 memcpy(mgmt_header->dest_addr, auth_data->bssid.address, ETH_ADDR);
970 memcpy(mgmt_header->src_addr, nic_address.address, ETH_ADDR);
971 memcpy(mgmt_header->bssid, auth_data->bssid.address, ETH_ADDR);
972
973 ieee80211_dev->ops->tx_handler(ieee80211_dev, buffer, buffer_size);
974
975 free(buffer);
976
977 ieee80211_dev->ops->bssid_change(ieee80211_dev);
978
979 return EOK;
980}
981
982static void ieee80211_process_auth_info(ieee80211_scan_result_link_t *ap_data,
983 void *buffer)
984{
985 uint8_t *it = (uint8_t *) buffer;
986
987 uint16_t *version = (uint16_t *) it;
988 if(uint16_t_le2host(*version) != 0x1) {
989 ap_data->scan_result.security.type = -1;
990 return;
991 }
992
993 it += sizeof(uint16_t);
994
995 uint32_t group_cipher = *(it+3);
996 switch(group_cipher) {
997 case IEEE80211_AUTH_CIPHER_TKIP:
998 ap_data->scan_result.security.group_alg =
999 IEEE80211_SECURITY_SUITE_TKIP;
1000 break;
1001 case IEEE80211_AUTH_CIPHER_CCMP:
1002 ap_data->scan_result.security.group_alg =
1003 IEEE80211_SECURITY_SUITE_CCMP;
1004 break;
1005 default:
1006 ap_data->scan_result.security.group_alg = -1;
1007 }
1008
1009 it += 4*sizeof(uint8_t);
1010
1011 uint16_t *pairwise_count = (uint16_t *) it;
1012 uint32_t pairwise_cipher = *(it+sizeof(uint16_t)+3);
1013 switch(pairwise_cipher) {
1014 case IEEE80211_AUTH_CIPHER_TKIP:
1015 ap_data->scan_result.security.pair_alg =
1016 IEEE80211_SECURITY_SUITE_TKIP;
1017 break;
1018 case IEEE80211_AUTH_CIPHER_CCMP:
1019 ap_data->scan_result.security.pair_alg =
1020 IEEE80211_SECURITY_SUITE_CCMP;
1021 break;
1022 default:
1023 ap_data->scan_result.security.pair_alg = -1;
1024 }
1025
1026 it += 2*sizeof(uint16_t) +
1027 uint16_t_le2host(*pairwise_count)*sizeof(uint32_t);
1028
1029 uint32_t auth_suite = *(it+3);
1030 switch(auth_suite) {
1031 case IEEE80211_AUTH_AKM_PSK:
1032 ap_data->scan_result.security.auth =
1033 IEEE80211_SECURITY_AUTH_PSK;
1034 break;
1035 case IEEE80211_AUTH_AKM_8021X:
1036 ap_data->scan_result.security.auth =
1037 IEEE80211_SECURITY_AUTH_8021X;
1038 break;
1039 default:
1040 ap_data->scan_result.security.auth = -1;
1041 }
1042}
1043
1044static uint32_t uint32_from_uint8_seq(uint8_t *seq)
1045{
1046 return (*seq << 24) + (*(seq+1) << 16) + (*(seq+2) << 8) + *(seq+3);
1047}
1048
1049static uint8_t *ieee80211_process_ies(ieee80211_dev_t *ieee80211_dev,
1050 ieee80211_scan_result_link_t *ap_data, void *buffer, size_t buffer_size)
1051{
1052 void *it = buffer;
1053 while((it + sizeof(ieee80211_ie_header_t)) < buffer + buffer_size) {
1054 ieee80211_ie_header_t *ie_header =
1055 (ieee80211_ie_header_t *) it;
1056 uint8_t *channel;
1057 switch(ie_header->element_id) {
1058 case IEEE80211_CHANNEL_IE:
1059 channel = (uint8_t *)
1060 (it + sizeof(ieee80211_ie_header_t));
1061 ap_data->scan_result.channel = *channel;
1062 break;
1063 case IEEE80211_RSN_IE:
1064 if(!ap_data)
1065 break;
1066 ap_data->scan_result.security.type =
1067 IEEE80211_SECURITY_WPA2;
1068 ieee80211_process_auth_info(ap_data,
1069 it + sizeof(ieee80211_ie_header_t));
1070 ap_data->rsn_copy_len = ie_header->length +
1071 sizeof(ieee80211_ie_header_t);
1072 memcpy(ap_data->rsn_copy,
1073 it,
1074 ap_data->rsn_copy_len);
1075 break;
1076 case IEEE80211_VENDOR_IE:
1077 if(uint32_from_uint8_seq(it +
1078 sizeof(ieee80211_ie_header_t)) ==
1079 WPA_OUI) {
1080 if(ap_data->scan_result.security.type ==
1081 IEEE80211_SECURITY_WPA2) {
1082 break;
1083 }
1084 ap_data->scan_result.security.type =
1085 IEEE80211_SECURITY_WPA;
1086 ieee80211_process_auth_info(ap_data,
1087 it +
1088 sizeof(ieee80211_ie_header_t) +
1089 sizeof(uint32_t));
1090 } else if(uint32_from_uint8_seq(it +
1091 sizeof(ieee80211_ie_header_t)) ==
1092 GTK_OUI) {
1093 return it +
1094 sizeof(ieee80211_ie_header_t) +
1095 sizeof(uint32_t) + 2;
1096 }
1097 }
1098 it += sizeof(ieee80211_ie_header_t) + ie_header->length;
1099 }
1100
1101 return NULL;
1102}
1103
1104/**
1105 * Process probe response and store results.
1106 *
1107 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
1108 * @param mgmt_header Pointer to start of management frame header.
1109 *
1110 * @return EOK if succeed, negative error code otherwise.
1111 */
1112static int ieee80211_process_probe_response(ieee80211_dev_t *ieee80211_dev,
1113 ieee80211_mgmt_header_t *mgmt_header, size_t buffer_size)
1114{
1115 ieee80211_beacon_start_t *beacon_body = (ieee80211_beacon_start_t *)
1116 ((void *)mgmt_header + sizeof(ieee80211_mgmt_header_t));
1117
1118 ieee80211_ie_header_t *ssid_ie_header = (ieee80211_ie_header_t *)
1119 ((void *)beacon_body + sizeof(ieee80211_beacon_start_t));
1120
1121 /* Not empty SSID. */
1122 if(ssid_ie_header->length > 0) {
1123 fibril_mutex_t *scan_mutex = &ieee80211_dev->ap_list.scan_mutex;
1124
1125 fibril_mutex_lock(scan_mutex);
1126
1127 ieee80211_scan_result_list_t *result_list =
1128 &ieee80211_dev->ap_list;
1129
1130 uint8_t *ssid_start = (uint8_t *) ((void *)ssid_ie_header +
1131 sizeof(ieee80211_ie_header_t));
1132 char ssid[IEEE80211_MAX_SSID_LENGTH];
1133 memcpy(ssid, ssid_start, ssid_ie_header->length);
1134 ssid[ssid_ie_header->length] = '\0';
1135
1136 /* Check whether SSID is already in results. */
1137 ieee80211_scan_result_list_foreach(*result_list, result) {
1138 if(!str_cmp(ssid, result->scan_result.ssid)) {
1139 result->last_beacon = time(NULL);
1140 fibril_mutex_unlock(scan_mutex);
1141 return EOK;
1142 }
1143 }
1144
1145 /* Results are full. */
1146 if(result_list->size == IEEE80211_MAX_RESULTS_LENGTH - 1) {
1147 fibril_mutex_unlock(scan_mutex);
1148 return EOK;
1149 }
1150
1151 ieee80211_scan_result_link_t *ap_data =
1152 malloc(sizeof(ieee80211_scan_result_link_t));
1153 memset(ap_data, 0, sizeof(ieee80211_scan_result_link_t));
1154 link_initialize(&ap_data->link);
1155
1156 memcpy(ap_data->scan_result.bssid.address,
1157 mgmt_header->bssid, ETH_ADDR);
1158 memcpy(ap_data->scan_result.ssid, ssid,
1159 ssid_ie_header->length + 1);
1160
1161 if(uint16_t_le2host(beacon_body->capability) & CAP_SECURITY) {
1162 ap_data->scan_result.security.type =
1163 IEEE80211_SECURITY_WEP;
1164 } else {
1165 ap_data->scan_result.security.type =
1166 IEEE80211_SECURITY_OPEN;
1167 ap_data->scan_result.security.auth = -1;
1168 ap_data->scan_result.security.pair_alg = -1;
1169 ap_data->scan_result.security.group_alg = -1;
1170 }
1171
1172 void *rest_ies_start = ssid_start + ssid_ie_header->length;
1173 size_t rest_buffer_size =
1174 buffer_size -
1175 sizeof(ieee80211_mgmt_header_t) -
1176 sizeof(ieee80211_beacon_start_t) -
1177 sizeof(ieee80211_ie_header_t) -
1178 ssid_ie_header->length;
1179
1180 ieee80211_process_ies(ieee80211_dev, ap_data, rest_ies_start,
1181 rest_buffer_size);
1182
1183 ap_data->last_beacon = time(NULL);
1184
1185 ieee80211_scan_result_list_append(result_list, ap_data);
1186
1187 fibril_mutex_unlock(scan_mutex);
1188 }
1189
1190 return EOK;
1191}
1192
1193/**
1194 * Process authentication response.
1195 *
1196 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
1197 * @param mgmt_header Pointer to start of management frame header.
1198 *
1199 * @return EOK if succeed, negative error code otherwise.
1200 */
1201static int ieee80211_process_auth_response(ieee80211_dev_t *ieee80211_dev,
1202 ieee80211_mgmt_header_t *mgmt_header)
1203{
1204 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
1205
1206 ieee80211_dev->current_auth_phase = IEEE80211_AUTH_AUTHENTICATED;
1207
1208 fibril_condvar_signal(&ieee80211_dev->gen_cond);
1209 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
1210
1211 return EOK;
1212}
1213
1214/**
1215 * Process association response.
1216 *
1217 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
1218 * @param mgmt_header Pointer to start of management frame header.
1219 *
1220 * @return EOK if succeed, negative error code otherwise.
1221 */
1222static int ieee80211_process_assoc_response(ieee80211_dev_t *ieee80211_dev,
1223 ieee80211_mgmt_header_t *mgmt_header)
1224{
1225 ieee80211_scan_result_t *auth_data =
1226 &ieee80211_dev->bssid_info.res_link->scan_result;
1227
1228 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
1229
1230 ieee80211_assoc_resp_body_t *assoc_resp =
1231 (ieee80211_assoc_resp_body_t *) ((void *)mgmt_header +
1232 sizeof(ieee80211_mgmt_header_t));
1233
1234 ieee80211_dev->bssid_info.aid = uint16_t_le2host(assoc_resp->aid);
1235 memcpy(auth_data->bssid.address, mgmt_header->bssid, ETH_ADDR);
1236
1237 ieee80211_dev->current_auth_phase = IEEE80211_AUTH_ASSOCIATED;
1238
1239 ieee80211_dev->ops->bssid_change(ieee80211_dev);
1240
1241 fibril_condvar_signal(&ieee80211_dev->gen_cond);
1242 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
1243
1244 return EOK;
1245}
1246
1247static int ieee80211_process_4way_handshake(ieee80211_dev_t *ieee80211_dev,
1248 void *buffer, size_t buffer_size)
1249{
1250 ieee80211_eapol_key_frame_t *key_frame =
1251 (ieee80211_eapol_key_frame_t *) buffer;
1252
1253 bool handshake_done = false;
1254
1255 ieee80211_scan_result_link_t *auth_link =
1256 ieee80211_dev->bssid_info.res_link;
1257
1258 ieee80211_scan_result_t *auth_data = &auth_link->scan_result;
1259 uint8_t *ptk = ieee80211_dev->bssid_info.ptk;
1260 uint8_t *gtk = ieee80211_dev->bssid_info.gtk;
1261
1262 size_t ptk_key_length, gtk_key_length;
1263 hash_func_t hash_sel;
1264 switch(auth_data->security.pair_alg) {
1265 case IEEE80211_SECURITY_SUITE_CCMP:
1266 ptk_key_length = IEEE80211_PTK_CCMP_LENGTH;
1267 hash_sel = HASH_SHA1;
1268 break;
1269 default:
1270 return ENOTSUP;
1271 }
1272
1273 switch(auth_data->security.group_alg) {
1274 case IEEE80211_SECURITY_SUITE_CCMP:
1275 gtk_key_length = IEEE80211_GTK_CCMP_LENGTH;
1276 break;
1277 default:
1278 return ENOTSUP;
1279 }
1280
1281 size_t output_size =
1282 sizeof(eth_header_t) +
1283 sizeof(ieee80211_eapol_key_frame_t);
1284
1285 if(!(uint16_t_be2host(key_frame->key_info) &
1286 IEEE80211_EAPOL_KEY_KEYINFO_SECURE)) {
1287 output_size += auth_link->rsn_copy_len;
1288 }
1289
1290 nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
1291 nic_address_t nic_address;
1292 nic_query_address(nic, &nic_address);
1293
1294 void *output_buffer = malloc(output_size);
1295 memset(output_buffer, 0, output_size);
1296
1297 /* Setup ethernet header. */
1298 eth_header_t *eth_header = (eth_header_t *) output_buffer;
1299 memcpy(eth_header->dest_addr, auth_data->bssid.address, ETH_ADDR);
1300 memcpy(eth_header->src_addr, nic_address.address, ETH_ADDR);
1301 eth_header->proto = host2uint16_t_be(ETH_TYPE_PAE);
1302
1303 ieee80211_eapol_key_frame_t *output_key_frame =
1304 (ieee80211_eapol_key_frame_t *)
1305 (output_buffer + sizeof(eth_header_t));
1306
1307 /* Copy content of incoming EAPOL-Key frame. */
1308 memcpy((void *) output_key_frame, buffer,
1309 sizeof(ieee80211_eapol_key_frame_t));
1310
1311 output_key_frame->proto_version = 0x1;
1312 output_key_frame->key_length = 0;
1313 output_key_frame->body_length =
1314 host2uint16_t_be(output_size - sizeof(eth_header_t)-4);
1315 output_key_frame->key_info &=
1316 ~host2uint16_t_be(
1317 IEEE80211_EAPOL_KEY_KEYINFO_ACK
1318 );
1319
1320 /*
1321 * Check if it is last or first incoming message in 4-way
1322 * handshake.
1323 */
1324 if(uint16_t_be2host(key_frame->key_info) &
1325 IEEE80211_EAPOL_KEY_KEYINFO_SECURE) {
1326 output_key_frame->key_info &=
1327 ~host2uint16_t_be(
1328 IEEE80211_EAPOL_KEY_KEYINFO_ENCDATA
1329 );
1330 output_key_frame->key_info &=
1331 ~host2uint16_t_be(
1332 IEEE80211_EAPOL_KEY_KEYINFO_INSTALL
1333 );
1334 output_key_frame->key_data_length = 0;
1335 output_key_frame->key_length = 0;
1336 memset(output_key_frame->key_nonce, 0, 32);
1337 memset(output_key_frame->key_mic, 0, 16);
1338 memset(output_key_frame->key_rsc, 0, 8);
1339 memset(output_key_frame->eapol_key_iv, 0, 16);
1340
1341 /* Derive GTK and save it. */
1342 uint16_t key_data_length =
1343 uint16_t_be2host(key_frame->key_data_length);
1344 uint16_t decrypt_len = key_data_length - 8;
1345 uint8_t key_data[decrypt_len];
1346 uint8_t *data_ptr = (uint8_t *) (buffer +
1347 sizeof(ieee80211_eapol_key_frame_t));
1348 if(ieee80211_aes_key_unwrap(ptk + KEK_OFFSET, data_ptr,
1349 key_data_length, key_data) == EOK) {
1350
1351 uint8_t *key_ptr = ieee80211_process_ies(ieee80211_dev,
1352 NULL, key_data, decrypt_len);
1353
1354 if(key_ptr) {
1355 memcpy(gtk, key_ptr, gtk_key_length);
1356 handshake_done = true;
1357 }
1358 }
1359 } else {
1360 output_key_frame->key_info |=
1361 host2uint16_t_be(
1362 IEEE80211_EAPOL_KEY_KEYINFO_MIC
1363 );
1364 output_key_frame->key_data_length =
1365 host2uint16_t_be(auth_link->rsn_copy_len);
1366 memcpy((void *)output_key_frame +
1367 sizeof(ieee80211_eapol_key_frame_t),
1368 auth_link->rsn_copy,
1369 auth_link->rsn_copy_len);
1370
1371 /* Compute PMK. */
1372 uint8_t pmk[PBKDF2_KEY_LENGTH];
1373 pbkdf2((uint8_t *) ieee80211_dev->bssid_info.password,
1374 str_size(ieee80211_dev->bssid_info.password),
1375 (uint8_t *) auth_data->ssid,
1376 str_size(auth_data->ssid), pmk, hash_sel);
1377
1378 uint8_t *anonce = key_frame->key_nonce;
1379
1380 /* Generate SNONCE. */
1381 uint8_t snonce[32];
1382 rnd_sequence(snonce, 32);
1383
1384 memcpy(output_key_frame->key_nonce, snonce, 32);
1385
1386 uint8_t *dest_addr = eth_header->dest_addr;
1387 uint8_t *src_addr = eth_header->src_addr;
1388
1389 /* Derive PTK and save it. */
1390 uint8_t prf_result[ptk_key_length];
1391 uint8_t crypt_data[PRF_CRYPT_DATA_LENGTH];
1392 memcpy(crypt_data,
1393 min_sequence(dest_addr, src_addr, ETH_ADDR),
1394 ETH_ADDR);
1395 memcpy(crypt_data + ETH_ADDR,
1396 max_sequence(dest_addr, src_addr, ETH_ADDR),
1397 ETH_ADDR);
1398 memcpy(crypt_data + 2*ETH_ADDR,
1399 min_sequence(anonce, snonce, 32),
1400 32);
1401 memcpy(crypt_data + 2*ETH_ADDR + 32,
1402 max_sequence(anonce, snonce, 32),
1403 32);
1404 ieee80211_prf(pmk, crypt_data, prf_result, hash_sel);
1405 memcpy(ptk, prf_result, ptk_key_length);
1406 }
1407
1408 /* Compute MIC of key frame data from KCK part of PTK. */
1409 uint8_t mic[SHA1_HASH_LENGTH];
1410 hmac(ptk, 16, (uint8_t *) output_key_frame,
1411 output_size - sizeof(eth_header_t), mic, hash_sel);
1412
1413 memcpy(output_key_frame->key_mic, mic, 16);
1414
1415 ieee80211_send_frame(nic, output_buffer, output_size);
1416
1417 free(output_buffer);
1418
1419 if(handshake_done) {
1420 /* Insert keys into device. */
1421
1422 /* Pairwise key. */
1423 ieee80211_key_config_t key_config;
1424 key_config.suite = auth_data->security.pair_alg;
1425 key_config.flags =
1426 IEEE80211_KEY_FLAG_TYPE_PAIRWISE;
1427 memcpy(key_config.data,
1428 ptk + TK_OFFSET,
1429 ptk_key_length - TK_OFFSET);
1430
1431 ieee80211_dev->ops->key_config(ieee80211_dev,
1432 &key_config, true);
1433
1434 /* Group key. */
1435 key_config.suite = auth_data->security.group_alg;
1436 key_config.flags =
1437 IEEE80211_KEY_FLAG_TYPE_GROUP;
1438 memcpy(key_config.data, gtk, gtk_key_length);
1439
1440 ieee80211_dev->ops->key_config(ieee80211_dev,
1441 &key_config, true);
1442
1443 /* Signal successful handshake completion. */
1444 fibril_mutex_lock(&ieee80211_dev->gen_mutex);
1445 fibril_condvar_signal(&ieee80211_dev->gen_cond);
1446 fibril_mutex_unlock(&ieee80211_dev->gen_mutex);
1447 }
1448
1449 return EOK;
1450}
1451
1452static int ieee80211_process_eapol_frame(ieee80211_dev_t *ieee80211_dev,
1453 void *buffer, size_t buffer_size)
1454{
1455 ieee80211_eapol_key_frame_t *key_frame =
1456 (ieee80211_eapol_key_frame_t *) buffer;
1457 if(ieee80211_is_eapol_key_frame(key_frame)) {
1458 return ieee80211_process_4way_handshake(ieee80211_dev, buffer,
1459 buffer_size);
1460 }
1461
1462 return EOK;
1463}
1464
1465/**
1466 * Process data frame.
1467 *
1468 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
1469 * @param buffer Data buffer starting with IEEE 802.11 data header.
1470 * @param buffer_size Size of buffer.
1471 *
1472 * @return EOK if succeed, negative error code otherwise.
1473 */
1474static int ieee80211_process_data(ieee80211_dev_t *ieee80211_dev,
1475 void *buffer, size_t buffer_size)
1476{
1477 ieee80211_data_header_t *data_header =
1478 (ieee80211_data_header_t *) buffer;
1479
1480 if(ieee80211_has_data_frame(data_header->frame_ctrl)) {
1481 nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
1482 size_t strip_length = sizeof(ieee80211_data_header_t) +
1483 ARRAY_SIZE(rfc1042_header);
1484
1485 /* TODO: Probably different by used security alg. */
1486 if(ieee80211_is_encrypted_frame(data_header->frame_ctrl)) {
1487 strip_length += 8;
1488 }
1489
1490 /* Process 4-way authentication handshake. */
1491 uint16_t *proto = (uint16_t *) (buffer + strip_length);
1492 if(uint16_t_be2host(*proto) == ETH_TYPE_PAE) {
1493 return ieee80211_process_eapol_frame(ieee80211_dev,
1494 buffer + strip_length + sizeof(uint16_t),
1495 buffer_size - strip_length - sizeof(uint16_t));
1496 }
1497
1498 /* Note: ETH protocol ID is already there, so we don't create
1499 * whole ETH header. */
1500 size_t frame_size =
1501 buffer_size - strip_length + sizeof(eth_header_t)-2;
1502 nic_frame_t *frame = nic_alloc_frame(nic, frame_size);
1503
1504 if(frame == NULL) {
1505 return ENOMEM;
1506 }
1507
1508 uint8_t *src_addr =
1509 ieee80211_is_fromds_frame(data_header->frame_ctrl) ?
1510 data_header->address3 : data_header->address2;
1511 uint8_t *dest_addr =
1512 ieee80211_is_tods_frame(data_header->frame_ctrl) ?
1513 data_header->address3 : data_header->address1;
1514
1515 eth_header_t *eth_header =
1516 (eth_header_t *) frame->data;
1517 memcpy(eth_header->src_addr, src_addr, ETH_ADDR);
1518 memcpy(eth_header->dest_addr, dest_addr, ETH_ADDR);
1519
1520 memcpy(frame->data + sizeof(eth_header_t)-2,
1521 buffer + strip_length,
1522 buffer_size - strip_length);
1523
1524 nic_received_frame(nic, frame);
1525 }
1526
1527 return EOK;
1528}
1529
1530/**
1531 * IEEE 802.11 RX frames handler.
1532 *
1533 * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
1534 * @param buffer Buffer with data.
1535 * @param buffer_size Size of buffer.
1536 *
1537 * @return EOK if succeed, negative error code otherwise.
1538 */
1539int ieee80211_rx_handler(ieee80211_dev_t *ieee80211_dev, void *buffer,
1540 size_t buffer_size)
1541{
1542 uint16_t frame_ctrl = *((uint16_t *) buffer);
1543 if(ieee80211_is_mgmt_frame(frame_ctrl)) {
1544 ieee80211_mgmt_header_t *mgmt_header =
1545 (ieee80211_mgmt_header_t *) buffer;
1546
1547 if(ieee80211_is_probe_response_frame(mgmt_header->frame_ctrl) ||
1548 ieee80211_is_beacon_frame(mgmt_header->frame_ctrl)) {
1549 return ieee80211_process_probe_response(ieee80211_dev,
1550 mgmt_header, buffer_size);
1551 }
1552
1553 if(ieee80211_is_auth_frame(mgmt_header->frame_ctrl)) {
1554 return ieee80211_process_auth_response(ieee80211_dev,
1555 mgmt_header);
1556 }
1557
1558 if(ieee80211_is_assoc_response_frame(mgmt_header->frame_ctrl)) {
1559 return ieee80211_process_assoc_response(ieee80211_dev,
1560 mgmt_header);
1561 }
1562 } else if(ieee80211_is_data_frame(frame_ctrl)) {
1563 return ieee80211_process_data(ieee80211_dev, buffer,
1564 buffer_size);
1565 }
1566
1567 return EOK;
1568}
1569
1570/** @}
1571 */
Note: See TracBrowser for help on using the repository browser.