source: mainline/uspace/lib/net/ieee80211/ieee80211.c@ 9e5a51c

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

Fixed PLL initialization value that blocked communication with external devices. Started implementing IEEE802.11 scanning and authentication functions.

  • Property mode set to 100644
File size: 8.2 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 libnet
30 * @{
31 */
32
33/** @file ieee80211.c
34 *
35 * IEEE 802.11 interface implementation.
36 */
37
38#include <errno.h>
39#include <byteorder.h>
40
41#include <ieee80211_impl.h>
42#include <ieee80211.h>
43
44/** Broadcast MAC address used to spread probe request through channel. */
45static const uint8_t ieee80211_broadcast_mac_addr[] = {
46 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
47};
48
49/** IEEE 802.11 b/g supported data rates in units of 500 kb/s. */
50static const uint8_t ieee80211bg_data_rates[] = {
51 2, 4, 11, 12, 18, 22, 24, 36
52};
53
54/** IEEE 802.11 b/g extended supported data rates in units of 500 kb/s.
55 *
56 * These are defined separately, because probe request message can
57 * only handle up to 8 data rates in supported rates IE.
58 */
59static const uint8_t ieee80211bg_ext_data_rates[] = {
60 48, 72, 96, 108
61};
62
63/** Network interface options for IEEE 802.11 driver. */
64static nic_iface_t ieee80211_nic_iface;
65
66/** Basic driver operations for IEEE 802.11 NIC driver. */
67static driver_ops_t ieee80211_nic_driver_ops;
68
69static int ieee80211_open(ddf_fun_t *fun)
70{
71 nic_t *nic_data = nic_get_from_ddf_fun(fun);
72 ieee80211_dev_t *ieee80211_dev = nic_get_specific(nic_data);
73
74 if(ieee80211_dev->started) {
75 return EOK;
76 } else {
77 ieee80211_dev->started = true;
78 }
79
80 int rc = ieee80211_dev->ops->start(ieee80211_dev);
81 if(rc != EOK)
82 return rc;
83
84 rc = ieee80211_dev->ops->scan(ieee80211_dev);
85 if(rc != EOK)
86 return rc;
87
88 return EOK;
89}
90
91/** Basic NIC device operations for IEEE802.11 driver. */
92static ddf_dev_ops_t ieee80211_nic_dev_ops = {
93 .open = ieee80211_open
94};
95
96static int ieee80211_set_operations(ieee80211_dev_t *ieee80211_dev,
97 ieee80211_ops_t *ieee80211_ops)
98{
99 /* IEEE802.11 start operation must be implemented. */
100 if(!ieee80211_ops->start)
101 return EINVAL;
102
103 /* IEEE802.11 TX handler must be implemented. */
104 if(!ieee80211_ops->tx_handler)
105 return EINVAL;
106
107 /* IEEE802.11 set frequency handler must be implemented. */
108 if(!ieee80211_ops->set_freq)
109 return EINVAL;
110
111 if(!ieee80211_ops->scan)
112 ieee80211_ops->scan = ieee80211_scan_impl;
113
114 ieee80211_dev->ops = ieee80211_ops;
115
116 return EOK;
117}
118
119/**
120 * Initialize an IEEE802.11 framework structure.
121 *
122 * @param ieee80211_dev Device structure to initialize.
123 * @param ieee80211_ops Structure with implemented IEEE802.11 operations.
124 *
125 * @return EOK if succeed, negative error code otherwise.
126 */
127int ieee80211_device_init(ieee80211_dev_t *ieee80211_dev, void *driver_data,
128 ddf_dev_t *ddf_dev)
129{
130 ieee80211_dev->ddf_dev = ddf_dev;
131 ieee80211_dev->driver_data = driver_data;
132 ieee80211_dev->started = false;
133 ieee80211_dev->current_op_mode = IEEE80211_OPMODE_STATION;
134
135 memcpy(ieee80211_dev->bssid_mask, ieee80211_broadcast_mac_addr,
136 ETH_ADDR);
137
138 /* Bind NIC to device */
139 nic_t *nic = nic_create_and_bind(ddf_dev);
140 if (!nic) {
141 return ENOMEM;
142 }
143
144 nic_set_specific(nic, ieee80211_dev);
145
146 return EOK;
147}
148
149/**
150 * IEEE802.11 WiFi framework initialization.
151 *
152 * @param ieee80211_dev Device structure to initialize.
153 * @param ieee80211_ops Structure with implemented IEEE802.11 operations.
154 *
155 * @return EOK if succeed, negative error code otherwise.
156 */
157int ieee80211_init(ieee80211_dev_t *ieee80211_dev,
158 ieee80211_ops_t *ieee80211_ops)
159{
160 int rc = ieee80211_set_operations(ieee80211_dev, ieee80211_ops);
161 if(rc != EOK)
162 return rc;
163
164 nic_driver_implement(&ieee80211_nic_driver_ops, &ieee80211_nic_dev_ops,
165 &ieee80211_nic_iface);
166
167 nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
168
169 /** TODO: Set NIC handlers here. */
170
171 ddf_fun_t *fun = ddf_fun_create(ieee80211_dev->ddf_dev, fun_exposed,
172 "port0");
173 if (fun == NULL) {
174 return EINVAL;
175 }
176
177 nic_set_ddf_fun(nic, fun);
178 ddf_fun_set_ops(fun, &ieee80211_nic_dev_ops);
179
180 rc = ddf_fun_bind(fun);
181 if (rc != EOK) {
182 ddf_fun_destroy(fun);
183 return rc;
184 }
185 rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC);
186 if (rc != EOK) {
187 ddf_fun_unbind(fun);
188 return rc;
189 }
190
191 return EOK;
192}
193
194static uint8_t ieee80211_freq_to_channel(uint16_t freq)
195{
196 return (freq - IEEE80211_FIRST_FREQ) / IEEE80211_CHANNEL_GAP + 1;
197}
198
199int ieee80211_probe_request(ieee80211_dev_t *ieee80211_dev)
200{
201 nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
202 nic_address_t nic_address;
203 nic_query_address(nic, &nic_address);
204
205 size_t data_rates_size =
206 sizeof(ieee80211bg_data_rates) /
207 sizeof(ieee80211bg_data_rates[0]);
208
209 size_t ext_data_rates_size =
210 sizeof(ieee80211bg_ext_data_rates) /
211 sizeof(ieee80211bg_ext_data_rates[0]);
212
213 /* 3 headers - (rates, ext rates, current channel) and their data
214 * lengths + pad.
215 */
216 size_t payload_size =
217 sizeof(ieee80211_ie_header_t) * 3 +
218 data_rates_size + ext_data_rates_size + sizeof(uint8_t) + 2;
219
220 size_t buffer_size = sizeof(ieee80211_mgmt_header_t) + payload_size;
221 void *buffer = malloc(buffer_size);
222 memset(buffer, 0, buffer_size);
223
224 ieee80211_mgmt_header_t *mgmt_header =
225 (ieee80211_mgmt_header_t *) buffer;
226
227 mgmt_header->frame_ctrl = host2uint16_t_le(
228 IEEE80211_MGMT_FRAME |
229 IEEE80211_MGMT_PROBE_REQ_FRAME
230 );
231 memcpy(mgmt_header->dest_addr, ieee80211_broadcast_mac_addr, ETH_ADDR);
232 memcpy(mgmt_header->src_addr, nic_address.address, ETH_ADDR);
233 memcpy(mgmt_header->bssid, ieee80211_broadcast_mac_addr, ETH_ADDR);
234
235 /* Jump to payload -> header + padding. */
236 uint8_t *it = buffer + sizeof(ieee80211_mgmt_header_t) + 2;
237
238 *it++ = IEEE80211_RATES_IE;
239 *it++ = data_rates_size;
240 memcpy(it, ieee80211bg_data_rates, data_rates_size);
241 it += data_rates_size;
242
243 *it++ = IEEE80211_EXT_RATES_IE;
244 *it++ = ext_data_rates_size;
245 memcpy(it, ieee80211bg_ext_data_rates, ext_data_rates_size);
246 it += ext_data_rates_size;
247
248 *it++ = IEEE80211_CHANNEL_IE;
249 *it++ = 1;
250 *it = ieee80211_freq_to_channel(ieee80211_dev->current_freq);
251
252 ieee80211_dev->ops->tx_handler(ieee80211_dev, buffer, buffer_size);
253
254 free(buffer);
255
256 return EOK;
257}
258
259int ieee80211_probe_auth(ieee80211_dev_t *ieee80211_dev)
260{
261 uint8_t test_bssid[] = {0x14, 0xF6, 0x5A, 0xAF, 0x5E, 0xB7};
262
263 nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
264 nic_address_t nic_address;
265 nic_query_address(nic, &nic_address);
266
267 size_t buffer_size = sizeof(ieee80211_mgmt_header_t) +
268 sizeof(ieee80211_auth_body_t);
269 void *buffer = malloc(buffer_size);
270 memset(buffer, 0, buffer_size);
271
272 ieee80211_mgmt_header_t *mgmt_header =
273 (ieee80211_mgmt_header_t *) buffer;
274
275 mgmt_header->frame_ctrl = host2uint16_t_le(
276 IEEE80211_MGMT_FRAME |
277 IEEE80211_MGMT_AUTH_FRAME
278 );
279 memcpy(mgmt_header->dest_addr, test_bssid, ETH_ADDR);
280 memcpy(mgmt_header->src_addr, nic_address.address, ETH_ADDR);
281 memcpy(mgmt_header->bssid, test_bssid, ETH_ADDR);
282
283 ieee80211_auth_body_t *auth_body =
284 (ieee80211_auth_body_t *)
285 (buffer + sizeof(ieee80211_mgmt_header_t));
286 auth_body->auth_alg = host2uint16_t_le(0);
287 auth_body->auth_trans_no = host2uint16_t_le(0);
288
289 ieee80211_dev->ops->tx_handler(ieee80211_dev, buffer, buffer_size);
290
291 free(buffer);
292
293 return EOK;
294}
295
296/** @}
297 */
Note: See TracBrowser for help on using the repository browser.