source: mainline/uspace/lib/ieee80211/src/ieee80211.c@ 963037b0

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

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

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