[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
|
---|
| 34 | *
|
---|
| 35 | * IEEE 802.11 interface implementation.
|
---|
| 36 | */
|
---|
| 37 |
|
---|
| 38 | #include <macros.h>
|
---|
| 39 | #include <errno.h>
|
---|
| 40 |
|
---|
| 41 | #include <ieee80211.h>
|
---|
| 42 | #include <ieee80211_impl.h>
|
---|
| 43 | #include <ieee80211_iface_impl.h>
|
---|
| 44 | #include <ieee80211_private.h>
|
---|
| 45 | #include <ops/ieee80211.h>
|
---|
| 46 |
|
---|
| 47 | /** Broadcast MAC address used to spread probe request through channel. */
|
---|
| 48 | static const uint8_t ieee80211_broadcast_mac_addr[] = {
|
---|
| 49 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
---|
| 50 | };
|
---|
| 51 |
|
---|
| 52 | /** IEEE 802.11 b/g supported data rates in units of 500 kb/s. */
|
---|
| 53 | static const uint8_t ieee80211bg_data_rates[] = {
|
---|
| 54 | 2, 4, 11, 12, 18, 22, 24, 36
|
---|
| 55 | };
|
---|
| 56 |
|
---|
| 57 | /** IEEE 802.11 b/g extended supported data rates in units of 500 kb/s.
|
---|
| 58 | *
|
---|
| 59 | * These are defined separately, because probe request message can
|
---|
| 60 | * only handle up to 8 data rates in supported rates IE.
|
---|
| 61 | */
|
---|
| 62 | static const uint8_t ieee80211bg_ext_data_rates[] = {
|
---|
| 63 | 48, 72, 96, 108
|
---|
| 64 | };
|
---|
| 65 |
|
---|
| 66 | inline bool ieee80211_is_data_frame(uint16_t frame_ctrl)
|
---|
| 67 | {
|
---|
| 68 | frame_ctrl = uint16_t_le2host(frame_ctrl);
|
---|
| 69 |
|
---|
| 70 | return (frame_ctrl & IEEE80211_FRAME_CTRL_FRAME_TYPE)
|
---|
| 71 | == IEEE80211_DATA_FRAME;
|
---|
| 72 | }
|
---|
| 73 |
|
---|
| 74 | inline bool ieee80211_is_mgmt_frame(uint16_t frame_ctrl)
|
---|
| 75 | {
|
---|
| 76 | frame_ctrl = uint16_t_le2host(frame_ctrl);
|
---|
| 77 |
|
---|
| 78 | return (frame_ctrl & IEEE80211_FRAME_CTRL_FRAME_TYPE)
|
---|
| 79 | == IEEE80211_MGMT_FRAME;
|
---|
| 80 | }
|
---|
| 81 |
|
---|
| 82 | inline bool ieee80211_is_beacon_frame(uint16_t frame_ctrl)
|
---|
| 83 | {
|
---|
| 84 | frame_ctrl = uint16_t_le2host(frame_ctrl);
|
---|
| 85 |
|
---|
| 86 | return (frame_ctrl & IEEE80211_FRAME_CTRL_FRAME_SUBTYPE)
|
---|
| 87 | == IEEE80211_MGMT_BEACON_FRAME;
|
---|
| 88 | }
|
---|
| 89 |
|
---|
| 90 | inline bool ieee80211_is_probe_response_frame(uint16_t frame_ctrl)
|
---|
| 91 | {
|
---|
| 92 | frame_ctrl = uint16_t_le2host(frame_ctrl);
|
---|
| 93 |
|
---|
| 94 | return (frame_ctrl & IEEE80211_FRAME_CTRL_FRAME_SUBTYPE)
|
---|
| 95 | == IEEE80211_MGMT_PROBE_RESP_FRAME;
|
---|
| 96 | }
|
---|
| 97 |
|
---|
| 98 | /**
|
---|
| 99 | * Get driver-specific structure for IEEE 802.11 device.
|
---|
| 100 | *
|
---|
| 101 | * @param ieee80211_dev IEEE 802.11 device.
|
---|
| 102 | *
|
---|
| 103 | * @return Driver-specific structure.
|
---|
| 104 | */
|
---|
| 105 | void *ieee80211_get_specific(ieee80211_dev_t* ieee80211_dev)
|
---|
| 106 | {
|
---|
| 107 | return ieee80211_dev->specific;
|
---|
| 108 | }
|
---|
| 109 |
|
---|
| 110 | /**
|
---|
| 111 | * Set driver-specific structure for IEEE 802.11 device.
|
---|
| 112 | *
|
---|
| 113 | * @param ieee80211_dev IEEE 802.11 device.
|
---|
| 114 | * @param specific Driver-specific structure.
|
---|
| 115 | */
|
---|
| 116 | void ieee80211_set_specific(ieee80211_dev_t* ieee80211_dev,
|
---|
| 117 | void *specific)
|
---|
| 118 | {
|
---|
| 119 | ieee80211_dev->specific = specific;
|
---|
| 120 | }
|
---|
| 121 |
|
---|
| 122 | /**
|
---|
| 123 | * Get related DDF device.
|
---|
| 124 | *
|
---|
| 125 | * @param ieee80211_dev IEEE 802.11 device.
|
---|
| 126 | *
|
---|
| 127 | * @return DDF device.
|
---|
| 128 | */
|
---|
| 129 | ddf_dev_t *ieee80211_get_ddf_dev(ieee80211_dev_t* ieee80211_dev)
|
---|
| 130 | {
|
---|
| 131 | return ieee80211_dev->ddf_dev;
|
---|
| 132 | }
|
---|
| 133 |
|
---|
| 134 | /**
|
---|
| 135 | * Query current operating mode of IEEE 802.11 device.
|
---|
| 136 | *
|
---|
| 137 | * @param ieee80211_dev IEEE 802.11 device.
|
---|
| 138 | *
|
---|
| 139 | * @return Current IEEE 802.11 operating mode.
|
---|
| 140 | */
|
---|
| 141 | ieee80211_operating_mode_t ieee80211_query_current_op_mode(ieee80211_dev_t* ieee80211_dev)
|
---|
| 142 | {
|
---|
| 143 | return ieee80211_dev->current_op_mode;
|
---|
| 144 | }
|
---|
| 145 |
|
---|
| 146 | /**
|
---|
| 147 | * Query current frequency of IEEE 802.11 device.
|
---|
| 148 | *
|
---|
| 149 | * @param ieee80211_dev IEEE 802.11 device.
|
---|
| 150 | *
|
---|
| 151 | * @return Current device operating frequency.
|
---|
| 152 | */
|
---|
| 153 | uint16_t ieee80211_query_current_freq(ieee80211_dev_t* ieee80211_dev)
|
---|
| 154 | {
|
---|
| 155 | return ieee80211_dev->current_freq;
|
---|
| 156 | }
|
---|
| 157 |
|
---|
| 158 | /**
|
---|
| 159 | * Report current operating mode for IEEE 802.11 device.
|
---|
| 160 | *
|
---|
| 161 | * @param ieee80211_dev IEEE 802.11 device.
|
---|
| 162 | * @param op_mode Current IEEE 802.11 operating mode.
|
---|
| 163 | */
|
---|
| 164 | void ieee80211_report_current_op_mode(ieee80211_dev_t* ieee80211_dev,
|
---|
| 165 | ieee80211_operating_mode_t op_mode)
|
---|
| 166 | {
|
---|
| 167 | ieee80211_dev->current_op_mode = op_mode;
|
---|
| 168 | }
|
---|
| 169 |
|
---|
| 170 | /**
|
---|
| 171 | * Report current frequency for IEEE 802.11 device.
|
---|
| 172 | *
|
---|
| 173 | * @param ieee80211_dev IEEE 802.11 device.
|
---|
| 174 | * @param freq Current device operating frequency.
|
---|
| 175 | */
|
---|
| 176 | void ieee80211_report_current_freq(ieee80211_dev_t* ieee80211_dev,
|
---|
| 177 | uint16_t freq)
|
---|
| 178 | {
|
---|
| 179 | ieee80211_dev->current_freq = freq;
|
---|
| 180 | }
|
---|
| 181 |
|
---|
| 182 | /**
|
---|
| 183 | * Implementation of NIC open callback for IEEE 802.11 devices.
|
---|
| 184 | *
|
---|
| 185 | * @param fun NIC function.
|
---|
| 186 | *
|
---|
| 187 | * @return EOK if succeed, negative error code otherwise.
|
---|
| 188 | */
|
---|
| 189 | static int ieee80211_open(ddf_fun_t *fun)
|
---|
| 190 | {
|
---|
| 191 | nic_t *nic_data = nic_get_from_ddf_fun(fun);
|
---|
| 192 | ieee80211_dev_t *ieee80211_dev = nic_get_specific(nic_data);
|
---|
| 193 |
|
---|
| 194 | if(ieee80211_dev->started) {
|
---|
| 195 | return EOK;
|
---|
| 196 | } else {
|
---|
| 197 | ieee80211_dev->started = true;
|
---|
| 198 | }
|
---|
| 199 |
|
---|
| 200 | int rc = ieee80211_dev->ops->start(ieee80211_dev);
|
---|
| 201 | if(rc != EOK)
|
---|
| 202 | return rc;
|
---|
| 203 |
|
---|
| 204 | rc = ieee80211_dev->ops->scan(ieee80211_dev);
|
---|
| 205 | if(rc != EOK)
|
---|
| 206 | return rc;
|
---|
| 207 |
|
---|
| 208 | return EOK;
|
---|
| 209 | }
|
---|
| 210 |
|
---|
| 211 | /**
|
---|
| 212 | * Send frame handler.
|
---|
| 213 | */
|
---|
| 214 | static void ieee80211_send_frame(nic_t *nic, void *data, size_t size)
|
---|
| 215 | {
|
---|
| 216 | ieee80211_dev_t *ieee80211_dev = (ieee80211_dev_t *)
|
---|
| 217 | nic_get_specific(nic);
|
---|
| 218 |
|
---|
| 219 | ieee80211_dev->ops->tx_handler(ieee80211_dev, data, size);
|
---|
| 220 | }
|
---|
| 221 |
|
---|
| 222 | /**
|
---|
| 223 | * Fill out IEEE 802.11 device functions implementations.
|
---|
| 224 | *
|
---|
| 225 | * @param ieee80211_dev IEEE 802.11 device.
|
---|
| 226 | * @param ieee80211_ops Callbacks implementation.
|
---|
| 227 | * @param ieee80211_iface Interface functions implementation.
|
---|
| 228 | * @param nic_iface NIC interface functions implementation.
|
---|
| 229 | * @param nic_dev_ops NIC device functions implementation.
|
---|
| 230 | *
|
---|
| 231 | * @return EINVAL when missing pointer to ieee80211_ops or ieee80211_iface,
|
---|
| 232 | * otherwise EOK.
|
---|
| 233 | */
|
---|
| 234 | static int ieee80211_implement(ieee80211_dev_t *ieee80211_dev,
|
---|
| 235 | ieee80211_ops_t *ieee80211_ops, ieee80211_iface_t *ieee80211_iface,
|
---|
| 236 | nic_iface_t *nic_iface, ddf_dev_ops_t *nic_dev_ops)
|
---|
| 237 | {
|
---|
| 238 | if(ieee80211_ops) {
|
---|
| 239 | if(!ieee80211_ops->start)
|
---|
| 240 | ieee80211_ops->start = ieee80211_start_impl;
|
---|
| 241 |
|
---|
| 242 | if(!ieee80211_ops->tx_handler)
|
---|
| 243 | ieee80211_ops->tx_handler = ieee80211_tx_handler_impl;
|
---|
| 244 |
|
---|
| 245 | if(!ieee80211_ops->set_freq)
|
---|
| 246 | ieee80211_ops->set_freq = ieee80211_set_freq_impl;
|
---|
| 247 |
|
---|
| 248 | if(!ieee80211_ops->scan)
|
---|
| 249 | ieee80211_ops->scan = ieee80211_scan_impl;
|
---|
| 250 | } else {
|
---|
| 251 | return EINVAL;
|
---|
| 252 | }
|
---|
| 253 |
|
---|
| 254 | ieee80211_dev->ops = ieee80211_ops;
|
---|
| 255 |
|
---|
| 256 | if(ieee80211_iface) {
|
---|
| 257 | if(nic_dev_ops)
|
---|
| 258 | if (!nic_dev_ops->interfaces[IEEE80211_DEV_IFACE])
|
---|
| 259 | nic_dev_ops->interfaces[IEEE80211_DEV_IFACE] = ieee80211_iface;
|
---|
| 260 |
|
---|
| 261 | if(!ieee80211_iface->get_scan_results)
|
---|
| 262 | ieee80211_iface->get_scan_results = ieee80211_get_scan_results_impl;
|
---|
| 263 |
|
---|
| 264 | if(!ieee80211_iface->connect)
|
---|
| 265 | ieee80211_iface->connect = ieee80211_connect_impl;
|
---|
| 266 | } else {
|
---|
| 267 | return EINVAL;
|
---|
| 268 | }
|
---|
| 269 |
|
---|
| 270 | if(nic_dev_ops) {
|
---|
| 271 | if(!nic_dev_ops->open)
|
---|
| 272 | nic_dev_ops->open = ieee80211_open;
|
---|
| 273 | } else {
|
---|
| 274 | return EINVAL;
|
---|
| 275 | }
|
---|
| 276 |
|
---|
| 277 | ieee80211_dev->iface = ieee80211_iface;
|
---|
| 278 |
|
---|
| 279 | nic_driver_implement(NULL, nic_dev_ops, nic_iface);
|
---|
| 280 |
|
---|
| 281 | return EOK;
|
---|
| 282 | }
|
---|
| 283 |
|
---|
| 284 | /**
|
---|
| 285 | * Allocate IEEE802.11 device structure.
|
---|
| 286 | *
|
---|
| 287 | * @return Pointer to allocated IEEE802.11 device structure.
|
---|
| 288 | */
|
---|
| 289 | ieee80211_dev_t *ieee80211_device_create()
|
---|
| 290 | {
|
---|
| 291 | return calloc(1, sizeof(ieee80211_dev_t));
|
---|
| 292 | }
|
---|
| 293 |
|
---|
| 294 | /**
|
---|
| 295 | * Initialize an IEEE802.11 framework structure.
|
---|
| 296 | *
|
---|
| 297 | * @param ieee80211_dev Device structure to initialize.
|
---|
| 298 | * @param ddf_dev Pointer to backing DDF device structure.
|
---|
| 299 | *
|
---|
| 300 | * @return EOK if succeed, negative error code otherwise.
|
---|
| 301 | */
|
---|
| 302 | int ieee80211_device_init(ieee80211_dev_t *ieee80211_dev, ddf_dev_t *ddf_dev)
|
---|
| 303 | {
|
---|
| 304 | ieee80211_dev->ddf_dev = ddf_dev;
|
---|
| 305 | ieee80211_dev->started = false;
|
---|
| 306 | ieee80211_dev->current_op_mode = IEEE80211_OPMODE_STATION;
|
---|
| 307 | memcpy(ieee80211_dev->bssid_mask.address, ieee80211_broadcast_mac_addr,
|
---|
| 308 | ETH_ADDR);
|
---|
| 309 |
|
---|
| 310 | /* Bind NIC to device */
|
---|
| 311 | nic_t *nic = nic_create_and_bind(ddf_dev);
|
---|
| 312 | if (!nic) {
|
---|
| 313 | return ENOMEM;
|
---|
| 314 | }
|
---|
| 315 |
|
---|
| 316 | nic_set_specific(nic, ieee80211_dev);
|
---|
| 317 |
|
---|
| 318 | return EOK;
|
---|
| 319 | }
|
---|
| 320 |
|
---|
| 321 | /**
|
---|
| 322 | * IEEE802.11 WiFi framework initialization.
|
---|
| 323 | *
|
---|
| 324 | * @param ieee80211_dev Device structure to initialize.
|
---|
| 325 | * @param ieee80211_ops Structure with implemented IEEE802.11 device operations.
|
---|
| 326 | * @param ieee80211_iface Structure with implemented IEEE802.11 interface
|
---|
| 327 | * operations.
|
---|
| 328 | *
|
---|
| 329 | * @return EOK if succeed, negative error code otherwise.
|
---|
| 330 | */
|
---|
| 331 | int ieee80211_init(ieee80211_dev_t *ieee80211_dev,
|
---|
| 332 | ieee80211_ops_t *ieee80211_ops, ieee80211_iface_t *ieee80211_iface,
|
---|
| 333 | nic_iface_t *ieee80211_nic_iface, ddf_dev_ops_t *ieee80211_nic_dev_ops)
|
---|
| 334 | {
|
---|
| 335 | int rc = ieee80211_implement(ieee80211_dev,
|
---|
| 336 | ieee80211_ops, ieee80211_iface,
|
---|
| 337 | ieee80211_nic_iface, ieee80211_nic_dev_ops);
|
---|
| 338 | if(rc != EOK) {
|
---|
| 339 | return rc;
|
---|
| 340 | }
|
---|
| 341 |
|
---|
| 342 | nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
|
---|
| 343 |
|
---|
| 344 | /** TODO: Set NIC handlers here. */
|
---|
| 345 | nic_set_send_frame_handler(nic, ieee80211_send_frame);
|
---|
| 346 |
|
---|
| 347 | ddf_fun_t *fun = ddf_fun_create(ieee80211_dev->ddf_dev, fun_exposed,
|
---|
| 348 | "port0");
|
---|
| 349 | if (fun == NULL) {
|
---|
| 350 | return EINVAL;
|
---|
| 351 | }
|
---|
| 352 |
|
---|
| 353 | nic_set_ddf_fun(nic, fun);
|
---|
| 354 | ddf_fun_set_ops(fun, ieee80211_nic_dev_ops);
|
---|
| 355 |
|
---|
| 356 | rc = ddf_fun_bind(fun);
|
---|
| 357 | if (rc != EOK) {
|
---|
| 358 | ddf_fun_destroy(fun);
|
---|
| 359 | return rc;
|
---|
| 360 | }
|
---|
| 361 | rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC);
|
---|
| 362 | if (rc != EOK) {
|
---|
| 363 | ddf_fun_unbind(fun);
|
---|
| 364 | return rc;
|
---|
| 365 | }
|
---|
| 366 | rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_IEEE80211);
|
---|
| 367 | if (rc != EOK) {
|
---|
| 368 | ddf_fun_unbind(fun);
|
---|
| 369 | return rc;
|
---|
| 370 | }
|
---|
| 371 |
|
---|
| 372 | return EOK;
|
---|
| 373 | }
|
---|
| 374 |
|
---|
| 375 | static uint8_t ieee80211_freq_to_channel(uint16_t freq)
|
---|
| 376 | {
|
---|
| 377 | return (freq - IEEE80211_FIRST_FREQ) / IEEE80211_CHANNEL_GAP + 1;
|
---|
| 378 | }
|
---|
| 379 |
|
---|
| 380 | /**
|
---|
| 381 | * Probe request implementation.
|
---|
| 382 | *
|
---|
| 383 | * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
|
---|
| 384 | *
|
---|
| 385 | * @return EOK if succeed, negative error code otherwise.
|
---|
| 386 | */
|
---|
| 387 | int ieee80211_probe_request(ieee80211_dev_t *ieee80211_dev)
|
---|
| 388 | {
|
---|
| 389 | nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
|
---|
| 390 | nic_address_t nic_address;
|
---|
| 391 | nic_query_address(nic, &nic_address);
|
---|
| 392 |
|
---|
| 393 | size_t data_rates_size = ARRAY_SIZE(ieee80211bg_data_rates);
|
---|
| 394 | size_t ext_data_rates_size = ARRAY_SIZE(ieee80211bg_ext_data_rates);
|
---|
| 395 |
|
---|
| 396 | /* 3 headers - (rates, ext rates, current channel) and their data
|
---|
| 397 | * lengths + pad.
|
---|
| 398 | */
|
---|
| 399 | size_t payload_size =
|
---|
| 400 | sizeof(ieee80211_ie_header_t) * 3 +
|
---|
| 401 | data_rates_size + ext_data_rates_size + sizeof(uint8_t) + 2;
|
---|
| 402 |
|
---|
| 403 | size_t buffer_size = sizeof(ieee80211_mgmt_header_t) + payload_size;
|
---|
| 404 | void *buffer = malloc(buffer_size);
|
---|
| 405 | memset(buffer, 0, buffer_size);
|
---|
| 406 |
|
---|
| 407 | ieee80211_mgmt_header_t *mgmt_header =
|
---|
| 408 | (ieee80211_mgmt_header_t *) buffer;
|
---|
| 409 |
|
---|
| 410 | mgmt_header->frame_ctrl = host2uint16_t_le(
|
---|
| 411 | IEEE80211_MGMT_FRAME |
|
---|
| 412 | IEEE80211_MGMT_PROBE_REQ_FRAME
|
---|
| 413 | );
|
---|
| 414 | memcpy(mgmt_header->dest_addr, ieee80211_broadcast_mac_addr, ETH_ADDR);
|
---|
| 415 | memcpy(mgmt_header->src_addr, nic_address.address, ETH_ADDR);
|
---|
| 416 | memcpy(mgmt_header->bssid, ieee80211_broadcast_mac_addr, ETH_ADDR);
|
---|
| 417 |
|
---|
| 418 | /* Jump to payload -> header + padding. */
|
---|
| 419 | ieee80211_ie_header_t *rates_ie_header = (ieee80211_ie_header_t *)
|
---|
| 420 | ((void *)buffer + sizeof(ieee80211_mgmt_header_t) + 2);
|
---|
| 421 | rates_ie_header->element_id = IEEE80211_RATES_IE;
|
---|
| 422 | rates_ie_header->length = data_rates_size;
|
---|
| 423 | memcpy(rates_ie_header + sizeof(ieee80211_ie_header_t),
|
---|
| 424 | ieee80211bg_data_rates,
|
---|
| 425 | data_rates_size);
|
---|
| 426 |
|
---|
| 427 | ieee80211_ie_header_t *ext_rates_ie_header = (ieee80211_ie_header_t *)
|
---|
| 428 | ((void *)rates_ie_header + sizeof(ieee80211_ie_header_t) +
|
---|
| 429 | data_rates_size);
|
---|
| 430 | ext_rates_ie_header->element_id = IEEE80211_EXT_RATES_IE;
|
---|
| 431 | ext_rates_ie_header->length = ext_data_rates_size;
|
---|
| 432 | memcpy(ext_rates_ie_header + sizeof(ieee80211_ie_header_t),
|
---|
| 433 | ieee80211bg_ext_data_rates,
|
---|
| 434 | ext_data_rates_size);
|
---|
| 435 |
|
---|
| 436 | ieee80211_ie_header_t *chan_ie_header = (ieee80211_ie_header_t *)
|
---|
| 437 | ((void *)ext_rates_ie_header + sizeof(ieee80211_ie_header_t) +
|
---|
| 438 | ext_data_rates_size);
|
---|
| 439 | chan_ie_header->element_id = IEEE80211_CHANNEL_IE;
|
---|
| 440 | chan_ie_header->length = 1;
|
---|
| 441 | uint8_t *it = (uint8_t *) ((void *)chan_ie_header +
|
---|
| 442 | sizeof(ieee80211_ie_header_t));
|
---|
| 443 | *it = ieee80211_freq_to_channel(ieee80211_dev->current_freq);
|
---|
| 444 |
|
---|
| 445 | ieee80211_dev->ops->tx_handler(ieee80211_dev, buffer, buffer_size);
|
---|
| 446 |
|
---|
| 447 | free(buffer);
|
---|
| 448 |
|
---|
| 449 | return EOK;
|
---|
| 450 | }
|
---|
| 451 |
|
---|
| 452 | /**
|
---|
| 453 | * Probe authentication implementation.
|
---|
| 454 | *
|
---|
| 455 | * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
|
---|
| 456 | *
|
---|
| 457 | * @return EOK if succeed, negative error code otherwise.
|
---|
| 458 | */
|
---|
| 459 | int ieee80211_probe_auth(ieee80211_dev_t *ieee80211_dev)
|
---|
| 460 | {
|
---|
| 461 | uint8_t test_bssid[] = {0x14, 0xF6, 0x5A, 0xAF, 0x5E, 0xB7};
|
---|
| 462 |
|
---|
| 463 | nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
|
---|
| 464 | nic_address_t nic_address;
|
---|
| 465 | nic_query_address(nic, &nic_address);
|
---|
| 466 |
|
---|
| 467 | size_t buffer_size = sizeof(ieee80211_mgmt_header_t) +
|
---|
| 468 | sizeof(ieee80211_auth_body_t);
|
---|
| 469 | void *buffer = malloc(buffer_size);
|
---|
| 470 | memset(buffer, 0, buffer_size);
|
---|
| 471 |
|
---|
| 472 | ieee80211_mgmt_header_t *mgmt_header =
|
---|
| 473 | (ieee80211_mgmt_header_t *) buffer;
|
---|
| 474 |
|
---|
| 475 | mgmt_header->frame_ctrl = host2uint16_t_le(
|
---|
| 476 | IEEE80211_MGMT_FRAME |
|
---|
| 477 | IEEE80211_MGMT_AUTH_FRAME
|
---|
| 478 | );
|
---|
| 479 | memcpy(mgmt_header->dest_addr, test_bssid, ETH_ADDR);
|
---|
| 480 | memcpy(mgmt_header->src_addr, nic_address.address, ETH_ADDR);
|
---|
| 481 | memcpy(mgmt_header->bssid, test_bssid, ETH_ADDR);
|
---|
| 482 |
|
---|
| 483 | ieee80211_auth_body_t *auth_body =
|
---|
| 484 | (ieee80211_auth_body_t *)
|
---|
| 485 | (buffer + sizeof(ieee80211_mgmt_header_t));
|
---|
| 486 | auth_body->auth_alg = host2uint16_t_le(0);
|
---|
| 487 | auth_body->auth_trans_no = host2uint16_t_le(0);
|
---|
| 488 |
|
---|
| 489 | ieee80211_dev->ops->tx_handler(ieee80211_dev, buffer, buffer_size);
|
---|
| 490 |
|
---|
| 491 | free(buffer);
|
---|
| 492 |
|
---|
| 493 | return EOK;
|
---|
| 494 | }
|
---|
| 495 |
|
---|
| 496 | /**
|
---|
| 497 | * Process probe response and store results.
|
---|
| 498 | *
|
---|
| 499 | * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
|
---|
| 500 | *
|
---|
| 501 | * @return EOK if succeed, negative error code otherwise.
|
---|
| 502 | */
|
---|
| 503 | static int ieee80211_process_probe_response(ieee80211_dev_t *ieee80211_dev,
|
---|
| 504 | ieee80211_mgmt_header_t *mgmt_header)
|
---|
| 505 | {
|
---|
| 506 | ieee80211_ie_header_t *ssid_ie_header = (ieee80211_ie_header_t *)
|
---|
| 507 | ((void *)mgmt_header + sizeof(ieee80211_mgmt_header_t) +
|
---|
| 508 | sizeof(ieee80211_beacon_start_t));
|
---|
| 509 |
|
---|
| 510 | if(ssid_ie_header->length > 0) {
|
---|
| 511 | uint8_t *results_length = &ieee80211_dev->ap_list.length;
|
---|
| 512 |
|
---|
| 513 | ieee80211_scan_result_t *ap_data =
|
---|
| 514 | &ieee80211_dev->ap_list.results[(*results_length)++];
|
---|
| 515 |
|
---|
| 516 | memset(ap_data, 0, sizeof(ieee80211_scan_result_t));
|
---|
| 517 |
|
---|
| 518 | uint8_t *ssid_start = (uint8_t *)
|
---|
| 519 | ((void *)ssid_ie_header +
|
---|
| 520 | sizeof(ieee80211_ie_header_t));
|
---|
| 521 |
|
---|
| 522 | memcpy(ap_data->bssid.address, mgmt_header->bssid, ETH_ADDR);
|
---|
| 523 | memcpy(ap_data->ssid, ssid_start, ssid_ie_header->length);
|
---|
| 524 | ap_data->ssid[ssid_ie_header->length] = '\0';
|
---|
| 525 | }
|
---|
| 526 |
|
---|
| 527 | return EOK;
|
---|
| 528 | }
|
---|
| 529 |
|
---|
| 530 | /**
|
---|
| 531 | * IEEE 802.11 RX frames handler.
|
---|
| 532 | *
|
---|
| 533 | * @param ieee80211_dev Pointer to IEEE 802.11 device structure.
|
---|
| 534 | * @param buffer Buffer with data.
|
---|
| 535 | * @param buffer_size Size of buffer.
|
---|
| 536 | *
|
---|
| 537 | * @return EOK if succeed, negative error code otherwise.
|
---|
| 538 | */
|
---|
| 539 | int ieee80211_rx_handler(ieee80211_dev_t *ieee80211_dev, void *buffer,
|
---|
| 540 | size_t buffer_size)
|
---|
| 541 | {
|
---|
| 542 | uint16_t frame_ctrl = *((uint16_t *) buffer);
|
---|
| 543 | if(ieee80211_is_mgmt_frame(frame_ctrl)) {
|
---|
| 544 | ieee80211_mgmt_header_t *mgmt_header =
|
---|
| 545 | (ieee80211_mgmt_header_t *) buffer;
|
---|
| 546 |
|
---|
| 547 | if(ieee80211_is_probe_response_frame(mgmt_header->frame_ctrl) ||
|
---|
| 548 | ieee80211_is_beacon_frame(mgmt_header->frame_ctrl)) {
|
---|
| 549 | return ieee80211_process_probe_response(ieee80211_dev,
|
---|
| 550 | mgmt_header);
|
---|
| 551 | }
|
---|
| 552 | // TODO
|
---|
| 553 | } else if(ieee80211_is_data_frame(frame_ctrl)) {
|
---|
| 554 | nic_t *nic = nic_get_from_ddf_dev(ieee80211_dev->ddf_dev);
|
---|
| 555 | size_t frame_size = buffer_size - sizeof(ieee80211_data_header_t);
|
---|
| 556 | nic_frame_t *frame = nic_alloc_frame(nic, frame_size);
|
---|
| 557 | if (frame != NULL) {
|
---|
| 558 | memcpy(frame->data,
|
---|
| 559 | buffer + sizeof(ieee80211_data_header_t),
|
---|
| 560 | frame_size);
|
---|
| 561 | nic_received_frame(nic, frame);
|
---|
| 562 | }
|
---|
| 563 | } else {
|
---|
| 564 | // TODO
|
---|
| 565 | }
|
---|
| 566 |
|
---|
| 567 | return EOK;
|
---|
| 568 | }
|
---|
| 569 |
|
---|
| 570 | /** @}
|
---|
| 571 | */
|
---|