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

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

A bit more change-proof max header length.

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