source: mainline/uspace/lib/ieee80211/src/ieee80211_impl.c@ f1380b7

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

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

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

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

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

  • Property mode set to 100644
File size: 10.1 KB
Line 
1/*
2 * Copyright (c) 2015 Jan Kolarik
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libieee80211
30 * @{
31 */
32
33/** @file ieee80211_impl.c
34 *
35 * IEEE 802.11 default device functions implementation.
36 */
37
38#include <stdio.h>
39#include <crypto.h>
40#include <stdlib.h>
41#include <errno.h>
42#include <ieee80211_impl.h>
43
44/** Default implementation of IEEE802.11 start function.
45 *
46 * @param ieee80211_dev Structure of IEEE802.11 device.
47 *
48 * @return EOK.
49 *
50 */
51errno_t ieee80211_start_impl(ieee80211_dev_t *ieee80211_dev)
52{
53 return EOK;
54}
55
56/** Default implementation of IEEE802.11 TX handler function.
57 *
58 * @param ieee80211_dev Structure of IEEE802.11 device.
59 * @param buffer Buffer with data to send.
60 * @param buffer_size Size of buffer.
61 *
62 * @return EOK.
63 *
64 */
65errno_t ieee80211_tx_handler_impl(ieee80211_dev_t *ieee80211_dev, void *buffer,
66 size_t buffer_size)
67{
68 return EOK;
69}
70
71/** Default implementation of IEEE802.11 set frequency function.
72 *
73 * @param ieee80211_dev Structure of IEEE802.11 device.
74 * @param freq Value of frequency to be switched on.
75 *
76 * @return EOK.
77 *
78 */
79errno_t ieee80211_set_freq_impl(ieee80211_dev_t *ieee80211_dev, uint16_t freq)
80{
81 return EOK;
82}
83
84/** Default implementation of IEEE802.11 BSSID change function.
85 *
86 * @param ieee80211_dev Structure of IEEE802.11 device.
87 *
88 * @return EOK.
89 *
90 */
91errno_t ieee80211_bssid_change_impl(ieee80211_dev_t *ieee80211_dev,
92 bool connected)
93{
94 return EOK;
95}
96
97/** Default implementation of IEEE802.11 key config function.
98 *
99 * @param ieee80211_dev Structure of IEEE802.11 device.
100 *
101 * @return EOK.
102 *
103 */
104errno_t ieee80211_key_config_impl(ieee80211_dev_t *ieee80211_dev,
105 ieee80211_key_config_t *key_conf, bool insert)
106{
107 return EOK;
108}
109
110/** Default implementation of IEEE802.11 scan function.
111 *
112 * @param ieee80211_dev Structure of IEEE802.11 device.
113 * @param clear Whether to clear current scan results.
114 *
115 * @return EOK if succeed, error code otherwise.
116 *
117 */
118errno_t ieee80211_scan_impl(ieee80211_dev_t *ieee80211_dev)
119{
120 fibril_mutex_lock(&ieee80211_dev->scan_mutex);
121
122 if (ieee80211_get_auth_phase(ieee80211_dev) ==
123 IEEE80211_AUTH_DISCONNECTED) {
124 fibril_mutex_lock(&ieee80211_dev->ap_list.results_mutex);
125
126 /* Remove old entries we don't receive beacons from. */
127 ieee80211_scan_result_list_t *result_list =
128 &ieee80211_dev->ap_list;
129
130 list_foreach_safe(result_list->list, cur_link, next_link) {
131 ieee80211_scan_result_link_t *cur_result =
132 list_get_instance(cur_link,
133 ieee80211_scan_result_link_t, link);
134
135 if ((time(NULL) - cur_result->last_beacon) >
136 MAX_KEEP_SCAN_SPAN_SEC)
137 ieee80211_scan_result_list_remove(result_list,
138 cur_result);
139 }
140
141 fibril_mutex_unlock(&ieee80211_dev->ap_list.results_mutex);
142
143 uint16_t orig_freq = ieee80211_dev->current_freq;
144
145 for (uint16_t freq = IEEE80211_FIRST_FREQ;
146 freq <= IEEE80211_MAX_FREQ; freq += IEEE80211_CHANNEL_GAP) {
147 if (ieee80211_pending_connect_request(ieee80211_dev))
148 break;
149
150 ieee80211_dev->ops->set_freq(ieee80211_dev, freq);
151 ieee80211_probe_request(ieee80211_dev, NULL);
152
153 /* Wait for probe responses. */
154 async_usleep(SCAN_CHANNEL_WAIT_USEC);
155 }
156
157 ieee80211_dev->ops->set_freq(ieee80211_dev, orig_freq);
158 }
159
160 fibril_mutex_unlock(&ieee80211_dev->scan_mutex);
161
162 return EOK;
163}
164
165/** Pseudorandom function used for IEEE 802.11 pairwise key computation.
166 *
167 * Using SHA1 hash algorithm.
168 *
169 * @param key Key with PBKDF2 encrypted passphrase.
170 * @param data Concatenated sequence of both MAC
171 * addresses and nonces.
172 * @param hash Output parameter for result hash.
173 * @param output_size Length of output sequence to be generated.
174 *
175 * @return EINVAL when key or data not specified,
176 * ENOMEM when pointer for output hash result
177 * is not allocated, otherwise EOK.
178 *
179 */
180errno_t ieee80211_prf(uint8_t *key, uint8_t *data, uint8_t *hash,
181 size_t output_size)
182{
183 if ((!key) || (!data))
184 return EINVAL;
185
186 if (!hash)
187 return ENOMEM;
188
189 size_t iters = ((output_size * 8) + 159) / 160;
190
191 const char *a = "Pairwise key expansion";
192 uint8_t result[HASH_SHA1 * iters];
193 uint8_t temp[HASH_SHA1];
194
195 size_t data_size = PRF_CRYPT_DATA_LENGTH + str_size(a) + 2;
196 uint8_t work_arr[data_size];
197 memset(work_arr, 0, data_size);
198
199 memcpy(work_arr, a, str_size(a));
200 memcpy(work_arr + str_size(a) + 1, data, PRF_CRYPT_DATA_LENGTH);
201
202 for (uint8_t i = 0; i < iters; i++) {
203 memcpy(work_arr + data_size - 1, &i, 1);
204 hmac(key, PBKDF2_KEY_LENGTH, work_arr, data_size, temp,
205 HASH_SHA1);
206 memcpy(result + i*HASH_SHA1, temp, HASH_SHA1);
207 }
208
209 memcpy(hash, result, output_size);
210
211 return EOK;
212}
213
214errno_t ieee80211_rc4_key_unwrap(uint8_t *key, uint8_t *data, size_t data_size,
215 uint8_t *output)
216{
217 return rc4(key, 32, data, data_size, 256, output);
218}
219
220errno_t ieee80211_aes_key_unwrap(uint8_t *kek, uint8_t *data, size_t data_size,
221 uint8_t *output)
222{
223 if ((!kek) || (!data))
224 return EINVAL;
225
226 if (!output)
227 return ENOMEM;
228
229 uint32_t n = data_size / 8 - 1;
230 uint8_t work_data[n * 8];
231 uint8_t work_input[AES_CIPHER_LENGTH];
232 uint8_t work_output[AES_CIPHER_LENGTH];
233 uint8_t *work_block;
234 uint8_t a[8];
235
236 memcpy(a, data, 8);
237
238 uint64_t mask = 0xff;
239 uint8_t shift, shb;
240
241 memcpy(work_data, data + 8, n * 8);
242 for (int j = 5; j >= 0; j--) {
243 for (int i = n; i > 0; i--) {
244 for (size_t k = 0; k < 8; k++) {
245 shift = 56 - 8 * k;
246 shb = ((n * j + i) & (mask << shift)) >> shift;
247 a[k] ^= shb;
248 }
249
250 work_block = work_data + (i - 1) * 8;
251 memcpy(work_input, a, 8);
252 memcpy(work_input + 8, work_block, 8);
253 aes_decrypt(kek, work_input, work_output);
254 memcpy(a, work_output, 8);
255 memcpy(work_data + (i - 1) * 8, work_output + 8, 8);
256 }
257 }
258
259 size_t it;
260 for (it = 0; it < 8; it++) {
261 if (a[it] != 0xa6)
262 break;
263 }
264
265 if (it == 8) {
266 memcpy(output, work_data, n * 8);
267 return EOK;
268 }
269
270 return EINVAL;
271}
272
273static void ieee80211_michael_mic_block(uint32_t *l, uint32_t *r,
274 uint32_t value)
275{
276 *l ^= value;
277 *r ^= rotl_uint32(*l, 17);
278 *l += *r;
279 *r ^= ((*l & 0x00ff00ff) << 8) | ((*l & 0xff00ff00) >> 8);
280 *l += *r;
281 *r ^= rotl_uint32(*l, 3);
282 *l += *r;
283 *r ^= rotr_uint32(*l, 2);
284 *l += *r;
285}
286
287errno_t ieee80211_michael_mic(uint8_t *key, uint8_t *buffer, size_t size,
288 uint8_t *mic)
289{
290 if ((!key) || (!buffer))
291 return EINVAL;
292
293 if (!mic)
294 return ENOMEM;
295
296 uint32_t l = uint32le_from_seq(key);
297 uint32_t r = uint32le_from_seq(key + 4);
298
299 ieee80211_data_header_t *data_header =
300 (ieee80211_data_header_t *) buffer;
301
302 uint8_t *data = buffer + sizeof(ieee80211_data_header_t) +
303 IEEE80211_TKIP_HEADER_LENGTH;
304 size_t data_size = size - sizeof(ieee80211_data_header_t) -
305 IEEE80211_TKIP_HEADER_LENGTH;
306
307 /* Process header. */
308 uint8_t *src_addr =
309 ieee80211_is_fromds_frame(data_header->frame_ctrl) ?
310 data_header->address3 : data_header->address2;
311 uint8_t *dest_addr =
312 ieee80211_is_tods_frame(data_header->frame_ctrl) ?
313 data_header->address3 : data_header->address1;
314
315 ieee80211_michael_mic_block(&l, &r, uint32le_from_seq(dest_addr));
316 ieee80211_michael_mic_block(&l, &r,
317 uint16le_from_seq(dest_addr + 4) |
318 (uint16le_from_seq(src_addr) << 16));
319 ieee80211_michael_mic_block(&l, &r, uint32le_from_seq(src_addr + 2));
320 ieee80211_michael_mic_block(&l, &r, 0);
321
322 /* Process data. */
323 size_t blocks = data_size / 4;
324 size_t pad = data_size % 4;
325
326 for (size_t k = 0; k < blocks; k++) {
327 ieee80211_michael_mic_block(&l, &r,
328 uint32le_from_seq(&data[k * 4]));
329 }
330
331 /* Add padding. */
332 uint32_t value = 0x5a;
333 for (size_t i = pad; i > 0; i--) {
334 value <<= 8;
335 value |= data[blocks * 4 + (i - 1)];
336 }
337
338 ieee80211_michael_mic_block(&l, &r, value);
339 ieee80211_michael_mic_block(&l, &r, 0);
340
341 l = host2uint32_t_le(l);
342 r = host2uint32_t_le(r);
343
344 memcpy(mic, &l, 4);
345 memcpy(mic + 4, &r, 4);
346
347 return EOK;
348}
349
350uint16_t uint16le_from_seq(void *seq)
351{
352 uint16_t *u16 = (uint16_t *) seq;
353 return uint16_t_le2host(*u16);
354}
355
356uint32_t uint32le_from_seq(void *seq)
357{
358 uint32_t *u32 = (uint32_t *) seq;
359 return uint32_t_le2host(*u32);
360}
361
362uint16_t uint16be_from_seq(void *seq)
363{
364 uint16_t *u16 = (uint16_t *) seq;
365 return uint16_t_be2host(*u16);
366}
367
368uint32_t uint32be_from_seq(void *seq)
369{
370 uint32_t *u32 = (uint32_t *) seq;
371 return uint32_t_be2host(*u32);
372}
373
374errno_t rnd_sequence(uint8_t *sequence, size_t length)
375{
376 if (!sequence)
377 return ENOMEM;
378
379 for (size_t i = 0; i < length; i++)
380 sequence[i] = (uint8_t) rand();
381
382 return EOK;
383}
384
385uint8_t *min_sequence(uint8_t *seq1, uint8_t *seq2, size_t size)
386{
387 if ((!seq1) || (!seq2))
388 return NULL;
389
390 for (size_t i = 0; i < size; i++) {
391 if (seq1[i] < seq2[i])
392 return seq1;
393 else if (seq1[i] > seq2[i])
394 return seq2;
395 }
396
397 return seq1;
398}
399
400uint8_t *max_sequence(uint8_t *seq1, uint8_t *seq2, size_t size)
401{
402 uint8_t *min = min_sequence(seq1, seq2, size);
403 if (min == seq1)
404 return seq2;
405
406 return seq1;
407}
408
409/** @}
410 */
Note: See TracBrowser for help on using the repository browser.