source: mainline/uspace/lib/ieee80211/src/ieee80211.c@ cc575ef9

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

Appending Michael MIC footer in TKIP communication, tested MIC algorithm itself, but needs testing on real data transmission

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