source: mainline/uspace/lib/ieee80211/src/ieee80211.c@ 08e103d4

Last change on this file since 08e103d4 was 08e103d4, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Use clearer naming for string length functions

This and the following commit change the names of functions, as well as
their documentation, to use unambiguous terms "bytes" and "code points"
instead of ambiguous terms "size", "length", and "characters".

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