├── .github └── workflows │ └── test.yml ├── .gitignore ├── .gitmodules ├── .lgtm.yml ├── CMakeLists.txt ├── COPYING ├── README.md ├── daemon ├── CMakeLists.txt ├── core.c ├── core.h ├── corewlan.h ├── corewlan.m ├── io.c ├── io.h ├── netutils.c ├── netutils.h └── owl.c ├── resources └── overview.png ├── src ├── CMakeLists.txt ├── channel.c ├── channel.h ├── circular_buffer.c ├── circular_buffer.h ├── crc32.c ├── crc32.h ├── election.c ├── election.h ├── frame.c ├── frame.h ├── hashmap.c ├── hashmap.h ├── ieee80211.h ├── log.c ├── log.h ├── peers.c ├── peers.h ├── rx.c ├── rx.h ├── schedule.c ├── schedule.h ├── siphash24.c ├── siphash24.h ├── state.c ├── state.h ├── sync.c ├── sync.h ├── tx.c ├── tx.h ├── version.c ├── version.h ├── wire.c └── wire.h └── tests ├── CMakeLists.txt ├── test_awdl_election.cpp ├── test_awdl_peers.cpp ├── test_awdl_sync.cpp └── test_wire.cpp /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Build and test 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ${{ matrix.os }} 9 | strategy: 10 | matrix: 11 | os: [ubuntu-latest, macos-latest] 12 | 13 | steps: 14 | - uses: actions/checkout@v1 15 | - name: Install dependencies 16 | if: startsWith(matrix.os, 'ubuntu') 17 | run: sudo apt install libpcap-dev libev-dev libnl-3-dev libnl-genl-3-dev libnl-route-3-dev 18 | - name: Install dependencies 19 | if: startsWith(matrix.os, 'macos') 20 | run: brew install libpcap libev 21 | - name: Checkout submodules 22 | run: git submodule update --init 23 | - name: Create build directory 24 | run: mkdir build 25 | - name: CMake 26 | run: cd build && cmake .. 27 | - name: make 28 | run: cd build && make 29 | - name: Run tests 30 | run: build/tests/tests 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IDEA 2 | .idea/ 3 | cmake-build-debug/ 4 | cmake-build-release/ 5 | 6 | # Build files 7 | build/ 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "googletest"] 2 | path = googletest 3 | url = https://github.com/google/googletest.git 4 | [submodule "radiotap"] 5 | path = radiotap 6 | url = https://github.com/radiotap/radiotap-library.git 7 | -------------------------------------------------------------------------------- /.lgtm.yml: -------------------------------------------------------------------------------- 1 | path_classifiers: 2 | library: 3 | - googletest 4 | - radiotap 5 | test: 6 | - tests 7 | extraction: 8 | cpp: 9 | prepare: 10 | # Ubuntu packages to be installed 11 | packages: 12 | - libpcap-dev 13 | - libev-dev 14 | - libnl-3-dev 15 | - libnl-genl-3-dev 16 | - libnl-route-3-dev 17 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(owl) 4 | 5 | if (CMAKE_C_COMPILER_ID MATCHES "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang") 6 | add_compile_options("-Wall" "-Wextra") 7 | endif () 8 | 9 | add_library(radiotap radiotap/radiotap.c) 10 | target_compile_definitions(radiotap PRIVATE -D_BSD_SOURCE -D_DEFAULT_SOURCE -DRADIOTAP_SUPPORT_OVERRIDES) 11 | 12 | add_subdirectory(src) 13 | 14 | add_subdirectory(daemon) 15 | 16 | option(INSTALL_GTEST "" OFF) 17 | add_subdirectory(googletest) 18 | 19 | add_subdirectory(tests) 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Open Wireless Link 2 | 3 | [![Language grade](https://img.shields.io/lgtm/grade/cpp/g/seemoo-lab/owl.svg?logo=lgtm&label=code%20quality)](https://lgtm.com/projects/g/seemoo-lab/owl/context:cpp) 4 | 5 | *Open Wireless Link (OWL)* is an open implementation of the Apple Wireless Direct Link (AWDL) ad hoc protocol for Linux and macOS written in C and part of the [Open Wireless Link project](https://owlink.org). 6 | 7 | OWL runs in user space and makes use of Linux’s Netlink API for Wi-Fi specific operations such as channel switching and to integrate itself in the Linux networking stack by providing a virtual network interface such that existing IPv6-capable programs can use AWDL without modification. 8 | 9 | You can use OWL to in combination with [OpenDrop](https://github.com/seemoo-lab/opendrop) to enable *Apple AirDrop* functionality on Linux-based systems [such as a Raspberry Pi 3](https://owlink.org/2019/05/16/howto-use-airdrop-on-raspberry-pi-3.html). 10 | 11 | ## Disclaimer 12 | 13 | OWL is experimental software and is the result of reverse engineering efforts by the [Open Wireless Link](https://owlink.org) project. 14 | Therefore, it does not support all features of AWDL or might be incompatible with future AWDL versions. 15 | OWL is not affiliated with or endorsed by Apple Inc. Use this code at your own risk. 16 | 17 | 18 | ## Requirements 19 | 20 | **Wi-Fi card with *active* monitor mode.** To use OWL, you will need a Wi-Fi card supporting active monitor mode with frame injection. We recommend the Atheros AR9280 chip (IEEE 802.11n) which we used to develop and test this code. Configurations that do not support *active* monitor mode, i.e., ACK received frames, might suffer from throughput degradation because the sender will re-transmit each frame up to 7 times as per the IEEE 802.11 standard. Have a look at [issue #9](https://github.com/seemoo-lab/owl/issues/9) if you want to find out whether your card meets the requirements. 21 | 22 | **No support for virtual machines and WSL.** OWL requires direct access to the Wi-Fi card which means that virtualized environments (except with USB or PCIe passthrough) and Windows Subsystem for Linux (WSL, see [issue #8](https://github.com/seemoo-lab/owl/issues/8)), are *not supported*. 23 | 24 | 25 | OWL requires `libpcap` for frame injection and reception, `libev` for event handling, and `libnl` (Linux only) for interactions with the system's networking stack which have to be installed on the target system. 26 | 27 | On Debian Linux, 28 | ```sh 29 | sudo apt install libpcap-dev libev-dev libnl-3-dev libnl-genl-3-dev libnl-route-3-dev 30 | ``` 31 | On Fedora Linux, 32 | ```sh 33 | sudo dnf install libpcap-devel libev-devel libnl3-devel 34 | ``` 35 | On macOS, you need to add support for tun/tap devices, e.g., via [tuntaposx](http://tuntaposx.sourceforge.net). You can install everything via [Homebrew](https://brew.sh): 36 | ```sh 37 | brew install libpcap libev 38 | brew cask install tuntap 39 | ``` 40 | 41 | ## Build from source 42 | 43 | The project is build using CMake. To build the project, simply clone this repository in `` and run 44 | ```sh 45 | cd 46 | git submodule update --init 47 | mkdir build 48 | cd build 49 | cmake .. 50 | make 51 | sudo make install 52 | ``` 53 | 54 | 55 | ## Use 56 | 57 | Simply run 58 | 59 | ```sh 60 | sudo owl -i 61 | ``` 62 | You can specify a wireless channel using the `-c` parameter. Available channels are 6, 44 and 149. Note that only some of these channels may be available for use in your country based on your regulatory domain. OWL will warn you if it is unable to use the specified channel, in which case you will only be able to monitor the network. 63 | On Linux, you can check which channels are available for use in your country using `iw list` in `Frequencies` section. A channel is not available if it is listed as `disabled` or `no IR`. 64 | 65 | You may increase the log level with `-v` and `-vv` and daemonize the program with `-D`. For other options, have a look at `daemon/owl.c`. 66 | **Warning:** do not use the `-N` flag in setups without Nexmon such as [this](https://owlink.org/2019/05/16/howto-use-airdrop-on-raspberry-pi-3.html) as it will likely [cause several problems](https://github.com/seemoo-lab/owl/issues/12#issuecomment-673651362). 67 | 68 | When started, OWL creates a virtual network interface `awdl0` with a link-local IPv6 address. Discovered AWDL peers are automatically added (and removed) to (and from) the system's neighbor table. Run `ip n` to see a list of all current neighbors. 69 | 70 | 71 | ## Architecture 72 | 73 | The following figure shows the core structure of OWL. 74 | 75 | ![Overview](resources/overview.png) 76 | 77 | 78 | ## Code Structure 79 | 80 | We provide a coarse structure of the most important components and files to facilitate navigating the code base. 81 | 82 | * `daemon/` Contains the active components that interact with the system. 83 | * `core.{c,h}` Schedules all relevant functions on the event loop. 84 | * `io.{c,h}` Platform-specific functions to send and receive frames. 85 | * `netutils.{c,h}` Platform-specific functions to interact with the system's networking stack. 86 | * `owl.c` Contains `main()` and sets up the `core` based on user arguments. 87 | * `googletest/` The runtime for running the tests. 88 | * `radiotap/` Library for parsing radiotap headers. 89 | * `src/` Contains platform-independent AWDL code. 90 | * `channel.{c,h}` Utilities for managing the channel sequence. 91 | * `election.{c,h}` Code for running the election process. 92 | * `frame.{c,h}` The corresponding header file contains the definitions of all TLVs. 93 | * `peers.{c,h}` Manages the peer table. 94 | * `rx.{c,h}` Functions for handling a received data and action frames including parsing TLVs. 95 | * `schedule.{c,h}` Functions to determine *when* and *which* frames should be sent. 96 | * `state.{c,h}` Consolidates the AWDL state. 97 | * `sync.{c,h}` Synchronization: managing (extended) availability windows. 98 | * `tx.{c,h}` Crafting valid data and action frames ready for transmission. 99 | * `version.{c,h}` Parse and create AWDL version numbers. 100 | * `wire.{c,h}` Mini-library for safely reading and writing primitives types from and to a frame buffer. 101 | * `tests/` The actual test cases for this repository. 102 | * `README.md` This file. 103 | 104 | 105 | ## Current Limitations/TODOs 106 | 107 | * OWL uses static election metric and counter values, so it either takes part as a slave (low values) or wins the election (high values). See `AWDL_ELECTION_METRIC_INIT` and `AWDL_ELECTION_COUNTER_INIT` and in `include/election.h`. 108 | * The channel sequence does not adjust itself automatically to current network load and/or other triggers. This would require a better understanding of Apple's implementation. Currently, the channel sequence is fixed when initializing. See `awdl_chanseq_init_static()` in `src/state.{c,h}`. 109 | * OWL does not allow a concurrent connection to an AP. This means, that when started, the Wi-Fi interface exclusively uses AWDL. To work around this, OWL could create a new monitor interface (instead of making the Wi-Fi interface one) and adjust its channel sequence to include the channel of the AP network. 110 | 111 | 112 | ## Our Papers 113 | 114 | * Milan Stute, Sashank Narain, Alex Mariotto, Alexander Heinrich, David Kreitschmann, Guevara Noubir, and Matthias Hollick. **A Billion Open Interfaces for Eve and Mallory: MitM, DoS, and Tracking Attacks on iOS and macOS Through Apple Wireless Direct Link.** *28th USENIX Security Symposium (USENIX Security ’19)*, August 14–16, 2019, Santa Clara, CA, USA. [Link](https://www.usenix.org/conference/usenixsecurity19/presentation/stute) 115 | 116 | * Milan Stute, David Kreitschmann, and Matthias Hollick. **One Billion Apples’ Secret Sauce: Recipe for the Apple Wireless Direct Link Ad hoc Protocol.** *The 24th Annual International Conference on Mobile Computing and Networking (MobiCom '18)*, October 29–November 2, 2018, New Delhi, India. ACM. [doi:10.1145/3241539.3241566](https://doi.org/10.1145/3241539.3241566) 117 | 118 | * Milan Stute, David Kreitschmann, and Matthias Hollick. **Demo: Linux Goes Apple Picking: Cross-Platform Ad hoc Communication with Apple Wireless Direct Link.** *The 24th Annual International Conference on Mobile Computing and Networking (MobiCom '18)*, October 29–November 2, 2018, New Delhi, India. ACM. [doi:10.1145/3241539.3267716](https://doi.org/10.1145/3241539.3267716) 119 | 120 | 121 | ## Contact 122 | 123 | * **Milan Stute** ([email](mailto:mstute@seemoo.tu-darmstadt.de), [web](https://seemoo.de/mstute)) 124 | -------------------------------------------------------------------------------- /daemon/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CMAKE_CXX_STANDARD 11) 2 | 3 | set(SOURCES PRIVATE 4 | io.c 5 | io.h 6 | core.c 7 | core.h 8 | netutils.c 9 | netutils.h) 10 | 11 | if (APPLE) 12 | list(APPEND SOURCES corewlan.m corewlan.h) 13 | endif () 14 | 15 | add_executable(owl "") 16 | 17 | target_sources(owl ${SOURCES} owl.c) 18 | 19 | find_path(pcap_INCLUDE pcap.h REQUIRED) 20 | find_library(pcap_LIBRARY pcap REQUIRED) 21 | 22 | find_path(ev_INCLUDE ev.h PATHS /usr/local/include REQUIRED) 23 | find_library(ev_LIBRARY ev REQUIRED) 24 | 25 | if (APPLE) 26 | find_library(FOUNDATION Foundation REQUIRED) 27 | find_library(COREWLAN CoreWLAN REQUIRED) 28 | find_library(SYSTEMCONFIGURATION SystemConfiguration REQUIRED) 29 | else () 30 | find_path(nl_INCLUDE netlink/version.h PATH_SUFFIXES libnl3 REQUIRED) 31 | find_library(nl_LIBRARY nl-3 REQUIRED) 32 | find_library(nlgenl_LIBRARY nl-genl-3 REQUIRED) 33 | find_library(nlroute_LIBRARY nl-route-3 REQUIRED) 34 | endif () 35 | 36 | target_include_directories(owl PRIVATE ${CMAKE_SOURCE_DIR}/src ${ev_INCLUDE} ${pcap_INCLUDE}) 37 | 38 | target_link_libraries(owl awdl ${pcap_LIBRARY} ${ev_LIBRARY}) 39 | if (APPLE) 40 | target_link_libraries(owl ${FOUNDATION} ${COREWLAN} ${SYSTEMCONFIGURATION}) 41 | else () 42 | target_include_directories(owl PRIVATE ${nl_INCLUDE}) 43 | target_link_libraries(owl ${nl_LIBRARY} ${nlgenl_LIBRARY} ${nlroute_LIBRARY}) 44 | endif () 45 | 46 | install(TARGETS owl DESTINATION bin) 47 | -------------------------------------------------------------------------------- /daemon/core.c: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #include "core.h" 21 | #include "netutils.h" 22 | 23 | #include "log.h" 24 | #include "wire.h" 25 | #include "rx.h" 26 | #include "tx.h" 27 | #include "schedule.h" 28 | 29 | #include 30 | 31 | #ifdef __APPLE__ 32 | # define SIGSTATS SIGINFO 33 | #else 34 | # define SIGSTATS SIGUSR1 35 | #endif 36 | 37 | #define ETHER_LENGTH 14 38 | #define ETHER_DST_OFFSET 0 39 | #define ETHER_SRC_OFFSET 6 40 | #define ETHER_ETHERTYPE_OFFSET 12 41 | 42 | #define POLL_NEW_UNICAST 0x1 43 | #define POLL_NEW_MULTICAST 0x2 44 | 45 | static void dump_frame(const char *dump_file, const struct pcap_pkthdr *hdr, const uint8_t *buf) { 46 | if (dump_file) { 47 | /* Make sure file exists because 'pcap_dump_open_append' does NOT create file for you */ 48 | fclose(fopen(dump_file, "a+")); 49 | pcap_t *p = pcap_open_dead(DLT_IEEE802_11_RADIO, 65535); 50 | pcap_dumper_t *dumper = pcap_dump_open_append(p, dump_file); 51 | pcap_dump((u_char *) dumper, hdr, buf); 52 | pcap_close(p); 53 | pcap_dump_close(dumper); 54 | } 55 | } 56 | 57 | static void ev_timer_rearm(struct ev_loop *loop, ev_timer *timer, double in) { 58 | ev_timer_stop(loop, timer); 59 | ev_timer_set(timer, in, 0.); 60 | ev_timer_start(loop, timer); 61 | } 62 | 63 | void wlan_device_ready(struct ev_loop *loop, ev_io *handle, int revents) { 64 | struct daemon_state *state = handle->data; 65 | int cnt = pcap_dispatch(state->io.wlan_handle, 1, &awdl_receive_frame, handle->data); 66 | if (cnt > 0) 67 | ev_feed_event(loop, handle, revents); 68 | } 69 | 70 | static int poll_host_device(struct daemon_state *state) { 71 | struct buf *buf = NULL; 72 | int result = 0; 73 | while (!state->next && !circular_buf_full(state->tx_queue_multicast)) { 74 | buf = buf_new_owned(ETHER_MAX_LEN); 75 | int len = buf_len(buf); 76 | if (host_recv(&state->io, (uint8_t *) buf_data(buf), &len) < 0) { 77 | goto wire_error; 78 | } else { 79 | bool is_multicast; 80 | struct ether_addr dst; 81 | buf_take(buf, buf_len(buf) - len); 82 | READ_ETHER_ADDR(buf, ETHER_DST_OFFSET, &dst); 83 | is_multicast = dst.ether_addr_octet[0] & 0x01; 84 | if (is_multicast) { 85 | circular_buf_put(state->tx_queue_multicast, buf); 86 | result |= POLL_NEW_MULTICAST; 87 | } else { /* unicast */ 88 | state->next = buf; 89 | result |= POLL_NEW_UNICAST; 90 | } 91 | } 92 | } 93 | return result; 94 | wire_error: 95 | if (buf) 96 | buf_free(buf); 97 | return result; 98 | } 99 | 100 | void host_device_ready(struct ev_loop *loop, ev_io *handle, int revents) { 101 | (void) loop; 102 | (void) revents; /* should always be EV_READ */ 103 | struct daemon_state *state = handle->data; 104 | 105 | int poll_result = poll_host_device(state); /* fill TX queues */ 106 | if (poll_result & POLL_NEW_MULTICAST) 107 | awdl_send_multicast(loop, &state->ev_state.tx_mcast_timer, 0); 108 | if (poll_result & POLL_NEW_UNICAST) 109 | awdl_send_unicast(loop, &state->ev_state.tx_timer, 0); 110 | } 111 | 112 | void awdl_receive_frame(uint8_t *user, const struct pcap_pkthdr *hdr, const uint8_t *buf) { 113 | #define MAX_NUM_AMPDU 16 /* TODO lookup this constant from the standard */ 114 | struct daemon_state *state = (void *) user; 115 | int result; 116 | const struct buf *frame = buf_new_const(buf, hdr->caplen); 117 | struct buf *data_arr[MAX_NUM_AMPDU]; 118 | struct buf **data = &data_arr[0]; 119 | result = awdl_rx(frame, &data, &state->awdl_state); 120 | if (result == RX_OK) { 121 | for (struct buf **data_start = &data_arr[0]; data_start < data; data_start++) { 122 | host_send(&state->io, buf_data(*data_start), buf_len(*data_start)); 123 | buf_free(*data_start); 124 | } 125 | } else if (result < RX_OK) { 126 | log_warn("unhandled frame (%d)", result); 127 | dump_frame(state->dump, hdr, buf); 128 | state->awdl_state.stats.rx_unknown++; 129 | } 130 | buf_free(frame); 131 | } 132 | 133 | int awdl_send_data(const struct buf *buf, const struct io_state *io_state, 134 | struct awdl_state *awdl_state, struct ieee80211_state *ieee80211_state) { 135 | uint8_t awdl_data[65535]; 136 | int awdl_data_len; 137 | uint16_t ethertype; 138 | struct ether_addr src, dst; 139 | uint64_t now; 140 | uint16_t period, slot, tu; 141 | 142 | READ_BE16(buf, ETHER_ETHERTYPE_OFFSET, ðertype); 143 | READ_ETHER_ADDR(buf, ETHER_DST_OFFSET, &dst); 144 | READ_ETHER_ADDR(buf, ETHER_SRC_OFFSET, &src); 145 | 146 | buf_strip(buf, ETHER_LENGTH); 147 | awdl_data_len = awdl_init_full_data_frame(awdl_data, &src, &dst, 148 | buf_data(buf), buf_len(buf), 149 | awdl_state, ieee80211_state); 150 | now = clock_time_us(); 151 | period = awdl_sync_current_eaw(now, &awdl_state->sync) / AWDL_CHANSEQ_LENGTH; 152 | slot = awdl_sync_current_eaw(now, &awdl_state->sync) % AWDL_CHANSEQ_LENGTH; 153 | tu = awdl_sync_next_aw_tu(now, &awdl_state->sync); 154 | log_trace("Send data (len %d) to %s (%u.%u.%u)", awdl_data_len, 155 | ether_ntoa(&dst), period, slot, tu); 156 | awdl_state->stats.tx_data++; 157 | if (wlan_send(io_state, awdl_data, awdl_data_len) < 0) 158 | return TX_FAIL; 159 | return TX_OK; 160 | 161 | wire_error: 162 | return TX_FAIL; 163 | } 164 | 165 | void awdl_send_action(struct daemon_state *state, enum awdl_action_type type) { 166 | uint8_t buf[65535]; 167 | int len; 168 | 169 | len = awdl_init_full_action_frame(buf, &state->awdl_state, &state->ieee80211_state, type); 170 | if (len < 0) 171 | return; 172 | log_trace("send %s", awdl_frame_as_str(type)); 173 | wlan_send(&state->io, buf, len); 174 | 175 | state->awdl_state.stats.tx_action++; 176 | } 177 | 178 | void awdl_send_psf(struct ev_loop *loop, ev_timer *handle, int revents) { 179 | (void) loop; 180 | (void) revents; 181 | awdl_send_action(handle->data, AWDL_ACTION_PSF); 182 | } 183 | 184 | void awdl_send_mif(struct ev_loop *loop, ev_timer *timer, int revents) { 185 | (void) revents; 186 | struct daemon_state *state = timer->data; 187 | struct awdl_state *awdl_state = &state->awdl_state; 188 | uint64_t now, next_aw, eaw_len; 189 | 190 | now = clock_time_us(); 191 | next_aw = awdl_sync_next_aw_us(now, &awdl_state->sync); 192 | eaw_len = awdl_state->sync.presence_mode * awdl_state->sync.aw_period; 193 | 194 | /* Schedule MIF in middle of sequence (if non-zero) */ 195 | if (awdl_chan_num(awdl_state->channel.current, awdl_state->channel.enc) > 0) 196 | awdl_send_action(state, AWDL_ACTION_MIF); 197 | 198 | /* schedule next in the middle of EAW */ 199 | ev_timer_rearm(loop, timer, usec_to_sec(next_aw + ieee80211_tu_to_usec(eaw_len / 2))); 200 | } 201 | 202 | void awdl_send_unicast(struct ev_loop *loop, ev_timer *timer, int revents) { 203 | (void) revents; 204 | struct daemon_state *state = timer->data; 205 | struct awdl_state *awdl_state = &state->awdl_state; 206 | uint64_t now = clock_time_us(); 207 | double in = 0; 208 | 209 | if (state->next) { /* we have something to send */ 210 | struct awdl_peer *peer; 211 | struct ether_addr dst; 212 | read_ether_addr(state->next, ETHER_DST_OFFSET, &dst); 213 | if (compare_ether_addr(&dst, &awdl_state->self_address) == 0) { 214 | /* send back to self */ 215 | host_send(&state->io, buf_data(state->next), buf_len(state->next)); 216 | buf_free(state->next); 217 | state->next = NULL; 218 | } else if (awdl_peer_get(awdl_state->peers.peers, &dst, &peer) < 0) { 219 | log_debug("Drop frame to non-peer %s", ether_ntoa(&dst)); 220 | buf_free(state->next); 221 | state->next = NULL; 222 | } else { 223 | in = awdl_can_send_unicast_in(awdl_state, peer, now, AWDL_UNICAST_GUARD_TU); 224 | if (in == 0) { /* send now */ 225 | awdl_send_data(state->next, &state->io, &state->awdl_state, &state->ieee80211_state); 226 | buf_free(state->next); 227 | state->next = NULL; 228 | state->awdl_state.stats.tx_data_unicast++; 229 | } else { /* try later */ 230 | if (in < 0) /* we are at the end of slot but within guard */ 231 | in = -in + usec_to_sec(ieee80211_tu_to_usec(AWDL_UNICAST_GUARD_TU)); 232 | } 233 | } 234 | } 235 | 236 | /* rearm if more unicast frames available */ 237 | if (state->next) { 238 | log_trace("awdl_send_unicast: retry in %lu TU", ieee80211_usec_to_tu(sec_to_usec(in))); 239 | ev_timer_rearm(loop, timer, in); 240 | } else { 241 | /* poll for more frames to keep queue full */ 242 | ev_feed_event(loop, &state->ev_state.read_host, 0); 243 | } 244 | } 245 | 246 | void awdl_send_multicast(struct ev_loop *loop, ev_timer *timer, int revents) { 247 | (void) revents; 248 | struct daemon_state *state = timer->data; 249 | struct awdl_state *awdl_state = &state->awdl_state; 250 | uint64_t now = clock_time_us(); 251 | double in = 0; 252 | 253 | if (!circular_buf_empty(state->tx_queue_multicast)) { /* we have something to send */ 254 | in = awdl_can_send_in(awdl_state, now, AWDL_MULTICAST_GUARD_TU); 255 | if (awdl_is_multicast_eaw(awdl_state, now) && (in == 0)) { /* we can send now */ 256 | void *next; 257 | circular_buf_get(state->tx_queue_multicast, &next, 0); 258 | awdl_send_data((struct buf *) next, &state->io, &state->awdl_state, &state->ieee80211_state); 259 | buf_free(next); 260 | state->awdl_state.stats.tx_data_multicast++; 261 | } else { /* try later */ 262 | if (in == 0) /* try again next EAW */ 263 | in = usec_to_sec(ieee80211_tu_to_usec(64)); 264 | else if (in < 0) /* we are at the end of slot but within guard */ 265 | in = -in + usec_to_sec(ieee80211_tu_to_usec(AWDL_MULTICAST_GUARD_TU)); 266 | } 267 | } 268 | 269 | /* rearm if more multicast frames available */ 270 | if (!circular_buf_empty(state->tx_queue_multicast)) { 271 | log_trace("awdl_send_multicast: retry in %lu TU", ieee80211_usec_to_tu(sec_to_usec(in))); 272 | ev_timer_rearm(loop, timer, in); 273 | } else { 274 | /* poll for more frames to keep queue full */ 275 | ev_feed_event(loop, &state->ev_state.read_host, 0); 276 | } 277 | } 278 | 279 | void awdl_switch_channel(struct ev_loop *loop, ev_timer *timer, int revents) { 280 | (void) revents; 281 | uint64_t now, next_aw; 282 | int slot; 283 | struct awdl_chan chan_new; 284 | int chan_num_new, chan_num_old; 285 | struct daemon_state *state = timer->data; 286 | struct awdl_state *awdl_state = &state->awdl_state; 287 | 288 | chan_num_old = awdl_chan_num(awdl_state->channel.current, awdl_state->channel.enc); 289 | 290 | now = clock_time_us(); 291 | slot = awdl_sync_current_eaw(now, &awdl_state->sync) % AWDL_CHANSEQ_LENGTH; 292 | chan_new = awdl_state->channel.sequence[slot]; 293 | chan_num_new = awdl_chan_num(awdl_state->channel.sequence[slot], awdl_state->channel.enc); 294 | 295 | if (chan_num_new && (chan_num_new != chan_num_old)) { 296 | log_debug("switch channel to %d (slot %d)", chan_num_new, slot); 297 | if (!state->io.wlan_is_file) { 298 | bool is_available; 299 | is_channel_available(state->io.wlan_ifindex, chan_num_new, &is_available); 300 | set_channel(state->io.wlan_ifindex, chan_num_new); 301 | } 302 | awdl_state->channel.current = chan_new; 303 | } 304 | 305 | next_aw = awdl_sync_next_aw_us(now, &awdl_state->sync); 306 | 307 | ev_timer_rearm(loop, timer, usec_to_sec(next_aw)); 308 | } 309 | 310 | static void awdl_neighbor_add(struct awdl_peer *p, void *_io_state) { 311 | struct io_state *io_state = _io_state; 312 | neighbor_add_rfc4291(io_state->host_ifindex, &p->addr); 313 | } 314 | 315 | static void awdl_neighbor_remove(struct awdl_peer *p, void *_io_state) { 316 | struct io_state *io_state = _io_state; 317 | neighbor_remove_rfc4291(io_state->host_ifindex, &p->addr); 318 | } 319 | 320 | void awdl_clean_peers(struct ev_loop *loop, ev_timer *timer, int revents) { 321 | (void) loop; 322 | (void) revents; /* should always be EV_TIMER */ 323 | uint64_t cutoff_time; 324 | struct daemon_state *state; 325 | 326 | state = (struct daemon_state *) timer->data; 327 | cutoff_time = clock_time_us() - state->awdl_state.peers.timeout; 328 | 329 | awdl_peers_remove(state->awdl_state.peers.peers, cutoff_time, 330 | state->awdl_state.peer_remove_cb, state->awdl_state.peer_remove_cb_data); 331 | 332 | /* TODO for now run election immediately after clean up; might consider seperate timer for this */ 333 | awdl_election_run(&state->awdl_state.election, &state->awdl_state.peers); 334 | 335 | ev_timer_again(loop, timer); 336 | } 337 | 338 | void awdl_print_stats(struct ev_loop *loop, ev_signal *handle, int revents) { 339 | (void) loop; 340 | (void) revents; /* should always be EV_TIMER */ 341 | struct awdl_stats *stats = &((struct daemon_state *) handle->data)->awdl_state.stats; 342 | 343 | log_info("STATISTICS"); 344 | log_info(" TX action %llu, data %llu, unicast %llu, multicast %llu", 345 | stats->tx_action, stats->tx_data, stats->tx_data_unicast, stats->tx_data_multicast); 346 | log_info(" RX action %llu, data %llu, unknown %llu", 347 | stats->rx_action, stats->rx_data, stats->rx_unknown); 348 | } 349 | 350 | int awdl_init(struct daemon_state *state, const char *wlan, const char *host, struct awdl_chan chan, const char *dump) { 351 | int err; 352 | char hostname[HOST_NAME_LENGTH_MAX + 1]; 353 | 354 | err = netutils_init(); 355 | if (err < 0) 356 | return err; 357 | 358 | err = io_state_init(&state->io, wlan, host, &AWDL_BSSID); 359 | if (err < 0) 360 | return err; 361 | 362 | err = get_hostname(hostname, sizeof(hostname)); 363 | if (err < 0) 364 | return err; 365 | 366 | awdl_init_state(&state->awdl_state, hostname, &state->io.if_ether_addr, chan, clock_time_us()); 367 | state->awdl_state.peer_cb = awdl_neighbor_add; 368 | state->awdl_state.peer_cb_data = (void *) &state->io; 369 | state->awdl_state.peer_remove_cb = awdl_neighbor_remove; 370 | state->awdl_state.peer_remove_cb_data = (void *) &state->io; 371 | ieee80211_init_state(&state->ieee80211_state); 372 | 373 | state->next = NULL; 374 | state->tx_queue_multicast = circular_buf_init(16); 375 | state->dump = dump; 376 | 377 | return 0; 378 | } 379 | 380 | void awdl_free(struct daemon_state *state) { 381 | circular_buf_free(state->tx_queue_multicast); 382 | io_state_free(&state->io); 383 | netutils_cleanup(); 384 | } 385 | 386 | void awdl_schedule(struct ev_loop *loop, struct daemon_state *state) { 387 | 388 | state->ev_state.loop = loop; 389 | 390 | /* Timer for channel switching */ 391 | state->ev_state.chan_timer.data = (void *) state; 392 | ev_timer_init(&state->ev_state.chan_timer, awdl_switch_channel, 0, 0); 393 | ev_timer_start(loop, &state->ev_state.chan_timer); 394 | 395 | /* Timer for peer table cleanup */ 396 | state->ev_state.peer_timer.data = (void *) state; 397 | ev_timer_init(&state->ev_state.peer_timer, awdl_clean_peers, 0, usec_to_sec(state->awdl_state.peers.clean_interval)); 398 | ev_timer_again(loop, &state->ev_state.peer_timer); 399 | 400 | /* Trigger frame reception from WLAN device */ 401 | state->ev_state.read_wlan.data = (void *) state; 402 | ev_io_init(&state->ev_state.read_wlan, wlan_device_ready, state->io.wlan_fd, EV_READ); 403 | ev_io_start(loop, &state->ev_state.read_wlan); 404 | 405 | /* Trigger frame reception from host device */ 406 | state->ev_state.read_host.data = (void *) state; 407 | ev_io_init(&state->ev_state.read_host, host_device_ready, state->io.host_fd, EV_READ); 408 | ev_io_start(loop, &state->ev_state.read_host); 409 | 410 | /* Timer for PSFs */ 411 | state->ev_state.psf_timer.data = (void *) state; 412 | ev_timer_init(&state->ev_state.psf_timer, awdl_send_psf, 413 | usec_to_sec(ieee80211_tu_to_usec(state->awdl_state.psf_interval)), 414 | usec_to_sec(ieee80211_tu_to_usec(state->awdl_state.psf_interval))); 415 | ev_timer_start(loop, &state->ev_state.psf_timer); 416 | 417 | /* Timer for MIFs */ 418 | state->ev_state.mif_timer.data = (void *) state; 419 | ev_timer_init(&state->ev_state.mif_timer, awdl_send_mif, 0, 0); 420 | ev_timer_start(loop, &state->ev_state.mif_timer); 421 | 422 | /* Timer for unicast packets */ 423 | state->ev_state.tx_timer.data = (void *) state; 424 | ev_timer_init(&state->ev_state.tx_timer, awdl_send_unicast, 0, 0); 425 | ev_timer_start(loop, &state->ev_state.tx_timer); 426 | 427 | /* Timer for multicast packets */ 428 | state->ev_state.tx_mcast_timer.data = (void *) state; 429 | ev_timer_init(&state->ev_state.tx_mcast_timer, awdl_send_multicast, 0, 0); 430 | ev_timer_start(loop, &state->ev_state.tx_mcast_timer); 431 | 432 | /* Register signal to print statistics */ 433 | state->ev_state.stats.data = (void *) state; 434 | ev_signal_init(&state->ev_state.stats, awdl_print_stats, SIGSTATS); 435 | ev_signal_start(loop, &state->ev_state.stats); 436 | } 437 | -------------------------------------------------------------------------------- /daemon/core.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #ifndef OWL_CORE_H 21 | #define OWL_CORE_H 22 | 23 | #include 24 | #include 25 | 26 | #include "state.h" 27 | #include "circular_buffer.h" 28 | #include "io.h" 29 | 30 | struct ev_state { 31 | struct ev_loop *loop; 32 | ev_timer mif_timer, psf_timer, tx_timer, tx_mcast_timer, chan_timer, peer_timer; 33 | ev_io read_wlan, read_host; 34 | ev_signal stats; 35 | }; 36 | 37 | struct daemon_state { 38 | struct io_state io; 39 | struct awdl_state awdl_state; 40 | struct ieee80211_state ieee80211_state; 41 | struct ev_state ev_state; 42 | struct buf *next; 43 | cbuf_handle_t tx_queue_multicast; 44 | const char *dump; 45 | }; 46 | 47 | int awdl_init(struct daemon_state *state, const char *wlan, const char *host, struct awdl_chan chan, const char *dump); 48 | 49 | void awdl_free(struct daemon_state *state); 50 | 51 | void awdl_schedule(struct ev_loop *loop, struct daemon_state *state); 52 | 53 | void wlan_device_ready(struct ev_loop *loop, ev_io *handle, int revents); 54 | 55 | void host_device_ready(struct ev_loop *loop, ev_io *handle, int revents); 56 | 57 | void awdl_receive_frame(uint8_t *user, const struct pcap_pkthdr *hdr, const uint8_t *buf); 58 | 59 | void awdl_send_action(struct daemon_state *state, enum awdl_action_type type); 60 | 61 | void awdl_send_psf(struct ev_loop *loop, ev_timer *handle, int revents); 62 | 63 | void awdl_send_mif(struct ev_loop *loop, ev_timer *handle, int revents); 64 | 65 | void awdl_send_unicast(struct ev_loop *loop, ev_timer *timer, int revents); 66 | 67 | void awdl_send_multicast(struct ev_loop *loop, ev_timer *timer, int revents); 68 | 69 | int awdl_send_data(const struct buf *buf, const struct io_state *io_state, 70 | struct awdl_state *awdl_state, struct ieee80211_state *ieee80211_state); 71 | 72 | void awdl_switch_channel(struct ev_loop *loop, ev_timer *handle, int revents); 73 | 74 | void awdl_clean_peers(struct ev_loop *loop, ev_timer *timer, int revents); 75 | 76 | void awdl_print_stats(struct ev_loop *loop, ev_signal *handle, int revents); 77 | 78 | #endif /* OWL_CORE_H */ 79 | -------------------------------------------------------------------------------- /daemon/corewlan.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #ifndef APPLE_COREWLAN_H 21 | #define APPLE_COREWLAN_H 22 | 23 | int corewlan_init(); 24 | 25 | void corewlan_free(); 26 | 27 | int corewlan_disassociate(int ifindex); 28 | 29 | int corewlan_set_channel(int ifindex, int channel); 30 | 31 | int corewlan_get_hostname(char *name, size_t len); 32 | 33 | #endif /* APPLE_COREWLAN_H */ 34 | -------------------------------------------------------------------------------- /daemon/corewlan.m: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #import 21 | #import 22 | #import 23 | #import 24 | #import 25 | #import 26 | 27 | static struct wlan_state { 28 | CWWiFiClient *client; 29 | CWInterface *iface; 30 | NSSet *supportedChannels; 31 | } state; 32 | 33 | int corewlan_init() { 34 | state.iface = NULL; 35 | state.supportedChannels = NULL; 36 | return 0; 37 | } 38 | 39 | void corewlan_free() { 40 | } 41 | 42 | int corewlan_disassociate(int ifindex) { 43 | if (!state.client) { 44 | state.client = [CWWiFiClient sharedWiFiClient]; 45 | } 46 | if (!state.iface) { 47 | char iface_cstr[IFNAMSIZ]; 48 | NSString *iface_str =[NSString stringWithUTF8String:if_indextoname(ifindex, iface_cstr)]; 49 | state.iface = [state.client interfaceWithName:iface_str]; 50 | } 51 | [state.iface disassociate]; 52 | return 0; 53 | } 54 | 55 | int corewlan_set_channel(int ifindex, int channel) { 56 | if (!state.client) { 57 | state.client = [CWWiFiClient sharedWiFiClient]; 58 | } 59 | if (!state.iface) { 60 | char iface_cstr[IFNAMSIZ]; 61 | NSString *iface_str = [NSString stringWithUTF8String:if_indextoname(ifindex, iface_cstr)]; 62 | state.iface = [state.client interfaceWithName:iface_str]; 63 | } 64 | if (!state.supportedChannels) 65 | state.supportedChannels = [state.iface supportedWLANChannels]; 66 | CWChannel* currentCandidate = NULL; 67 | for (CWChannel* chan in state.supportedChannels) { 68 | if ([chan channelNumber] != channel) 69 | continue; 70 | if (!currentCandidate || [chan channelWidth] > [currentCandidate channelWidth]) 71 | currentCandidate = chan; 72 | } 73 | if (!currentCandidate) 74 | return -1; 75 | NSError* err; 76 | [state.iface setWLANChannel:currentCandidate error:&err]; 77 | return !err; 78 | } 79 | 80 | int corewlan_get_hostname(char *name, size_t len) { 81 | NSString *computerName = [(NSString *) SCDynamicStoreCopyComputerName(NULL, NULL) autorelease]; 82 | strlcpy(name, [computerName UTF8String], len); 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /daemon/io.c: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #ifndef __APPLE__ 28 | #include 29 | #else 30 | #include 31 | #include 32 | #include 33 | #include 34 | #endif /* __APPLE__ */ 35 | #include "io.h" 36 | #include "netutils.h" 37 | 38 | #include 39 | #include 40 | 41 | static int open_nonblocking_device(const char *dev, pcap_t **pcap_handle, const struct ether_addr *bssid_filter) { 42 | char errbuf[PCAP_ERRBUF_SIZE]; 43 | pcap_t *handle; 44 | struct bpf_program filter; 45 | int fd; 46 | char filter_str[128]; 47 | 48 | handle = pcap_create(dev, errbuf); 49 | if (handle == NULL) { 50 | log_error("pcap: unable to open device %s (%s)", dev, errbuf); 51 | return -1; 52 | } 53 | 54 | pcap_set_snaplen(handle, 65535); 55 | pcap_set_promisc(handle, 1); 56 | #ifdef __APPLE__ 57 | /* On Linux, we activate monitor mode via nl80211 */ 58 | pcap_set_rfmon(handle, 1); 59 | #endif /* __APPLE__ */ 60 | 61 | pcap_set_timeout(handle, 1); 62 | 63 | if (pcap_activate(handle) < 0) { 64 | log_error("pcap: unable to activate device %s (%s)", dev, pcap_geterr(handle)); 65 | pcap_close(handle); 66 | return -1; 67 | } 68 | 69 | if (pcap_setnonblock(handle, 1, errbuf)) { 70 | log_error("pcap: cannot set to non-blocking mode (%s)", errbuf); 71 | pcap_close(handle); 72 | return -1; 73 | } 74 | 75 | /* TODO direction does not seem to have an effect (we get our own frames every time we poll) */ 76 | if (pcap_setdirection(handle, PCAP_D_IN)) { 77 | log_warn("pcap: unable to monitor only incoming traffic on device %s (%s)", dev, pcap_geterr(handle)); 78 | } 79 | 80 | if (pcap_datalink(handle) != DLT_IEEE802_11_RADIO) { 81 | log_error("pcap: device %s does not support radiotap headers", dev); 82 | pcap_close(handle); 83 | return -1; 84 | } 85 | 86 | snprintf(filter_str, sizeof(filter_str), "wlan addr3 %s", ether_ntoa(bssid_filter)); 87 | if (pcap_compile(handle, &filter, filter_str, 1, PCAP_NETMASK_UNKNOWN) == -1) { 88 | log_error("pcap: could not create filter (%s)", pcap_geterr(handle)); 89 | return -1; 90 | } 91 | 92 | if (pcap_setfilter(handle, &filter) == -1) { 93 | log_error("pcap: could not set filter (%s)", pcap_geterr(handle)); 94 | return -1; 95 | } 96 | 97 | if ((fd = pcap_get_selectable_fd(handle)) == -1) { 98 | log_error("pcap: unable to get fd"); 99 | return -1; 100 | } 101 | 102 | *pcap_handle = handle; 103 | 104 | return fd; 105 | } 106 | 107 | static int open_savefile(const char *filename, pcap_t **pcap_handle) { 108 | char errbuf[PCAP_ERRBUF_SIZE]; 109 | int fd; 110 | 111 | pcap_t *handle = pcap_open_offline(filename, errbuf); 112 | if (!handle) { 113 | log_trace("pcap: unable to open savefile (%s)", errbuf); 114 | return -1; 115 | } 116 | 117 | if ((fd = pcap_get_selectable_fd(handle)) == -1) { 118 | log_trace("pcap: unable to get fd"); 119 | return -1; 120 | } 121 | 122 | *pcap_handle = handle; 123 | 124 | return fd; 125 | } 126 | 127 | static int open_tun(char *dev, const struct ether_addr *self) { 128 | #ifndef __APPLE__ 129 | static int one = 1; 130 | struct ifreq ifr; 131 | int fd, err, s; 132 | 133 | if ((fd = open("/dev/net/tun", O_RDWR)) < 0) { 134 | log_error("tun: unable to open tun device %d", fd); 135 | return fd; 136 | } 137 | 138 | memset(&ifr, 0, sizeof(ifr)); 139 | 140 | /* Flags: IFF_TUN - TUN device (no Ethernet headers) 141 | * IFF_TAP - TAP device 142 | * IFF_NO_PI - Do not provide packet information 143 | */ 144 | ifr.ifr_flags = IFF_TAP | IFF_NO_PI; 145 | if (*dev) 146 | strncpy(ifr.ifr_name, dev, IFNAMSIZ); 147 | 148 | if ((err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0) { 149 | close(fd); 150 | return err; 151 | } 152 | strcpy(dev, ifr.ifr_name); 153 | 154 | /* Set non-blocking mode */ 155 | if ((err = ioctl(fd, FIONBIO, &one)) < 0) { 156 | close(fd); 157 | return err; 158 | } 159 | 160 | // Create a socket for ioctl 161 | s = socket(AF_INET6, SOCK_DGRAM, 0); 162 | 163 | // Set HW address 164 | ifr.ifr_hwaddr.sa_family = 1; /* ARPHRD_ETHER */ 165 | memcpy(ifr.ifr_hwaddr.sa_data, self, 6); 166 | if ((err = ioctl(s, SIOCSIFHWADDR, &ifr)) < 0) { 167 | log_error("tun: unable to set HW address"); 168 | close(fd); 169 | return err; 170 | } 171 | 172 | // Get current flags and set them 173 | ioctl(s, SIOCGIFFLAGS, &ifr); 174 | ifr.ifr_flags |= IFF_UP | IFF_RUNNING; 175 | if ((err = ioctl(s, SIOCSIFFLAGS, &ifr)) < 0) { 176 | log_error("tun: unable to set up"); 177 | close(fd); 178 | return err; 179 | } 180 | 181 | /* Set reduced MTU */ 182 | ifr.ifr_mtu = 1450; /* TODO arbitary limit to fit all headers */ 183 | if ((err = ioctl(s, SIOCSIFMTU, (void *) &ifr)) < 0) { 184 | log_error("tun: unable to set MTU"); 185 | close(fd); 186 | return err; 187 | } 188 | 189 | close(s); 190 | 191 | return fd; 192 | #else 193 | for (int i = 0; i < 16; ++i) { 194 | char tuntap[IFNAMSIZ]; 195 | sprintf(tuntap, "/dev/tap%d", i); 196 | 197 | int fd = open(tuntap, O_RDWR); 198 | if (fd > 0) { 199 | struct ifreq ifr; 200 | struct in6_aliasreq ifr6; 201 | int err, s; 202 | 203 | if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { 204 | log_error("fcntl error on %s", tuntap); 205 | return -errno; 206 | } 207 | 208 | sprintf(dev, "tap%d", i); 209 | 210 | // Create a socket for ioctl 211 | s = socket(AF_INET6, SOCK_DGRAM, 0); 212 | 213 | // Set HW address 214 | strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); 215 | ifr.ifr_addr.sa_len = sizeof(struct ether_addr); 216 | ifr.ifr_addr.sa_family = AF_LINK; 217 | memcpy(ifr.ifr_addr.sa_data, self, sizeof(struct ether_addr)); 218 | if ((err = ioctl(s, SIOCSIFLLADDR, (caddr_t) &ifr)) < 0) { 219 | log_error("tun: unable to set HW address %s", ether_ntoa(self)); 220 | close(fd); 221 | return err; 222 | } 223 | 224 | /* Set reduced MTU */ 225 | ifr.ifr_mtu = 1450; /* TODO arbitary limit to fit all headers */ 226 | if ((err = ioctl(s, SIOCSIFMTU, (caddr_t) &ifr)) < 0) { 227 | log_error("tun: unable to set MTU"); 228 | close(fd); 229 | return err; 230 | } 231 | 232 | /* Set IPv6 address */ 233 | memset(&ifr6, 0, sizeof(ifr6)); 234 | strlcpy(ifr6.ifra_name, dev, sizeof(ifr6.ifra_name)); 235 | 236 | ifr6.ifra_addr.sin6_len = sizeof(ifr6.ifra_addr); 237 | ifr6.ifra_addr.sin6_family = AF_INET6; 238 | rfc4291_addr(self, &ifr6.ifra_addr.sin6_addr); 239 | 240 | ifr6.ifra_prefixmask.sin6_len = sizeof(ifr6.ifra_prefixmask); 241 | ifr6.ifra_prefixmask.sin6_family = AF_INET6; 242 | memset((void *) &ifr6.ifra_prefixmask.sin6_addr, 0x00, sizeof(ifr6.ifra_prefixmask)); 243 | for (int i = 0; i < 8; i++) /* prefix length: 64 */ 244 | ifr6.ifra_prefixmask.sin6_addr.s6_addr[i] = 0xff; 245 | 246 | if (ioctl(s, SIOCAIFADDR_IN6, (caddr_t) &ifr6) < 0) { 247 | log_error("tun: unable to set IPv6 address, %s", strerror(errno)); 248 | close(fd); 249 | return -errno; 250 | } 251 | 252 | close(s); 253 | 254 | return fd; 255 | } 256 | } 257 | log_error("tun: cannot open available device"); 258 | return -1; 259 | #endif /* __APPLE__ */ 260 | } 261 | 262 | static int io_state_init_wlan_try_savefile(struct io_state *state) { 263 | int err; 264 | 265 | state->wlan_fd = open_savefile(state->wlan_ifname, &state->wlan_handle); 266 | if ((err = state->wlan_fd) < 0) 267 | return err; 268 | state->wlan_is_file = 1; 269 | state->wlan_ifindex = 0; 270 | 271 | return 0; 272 | } 273 | 274 | static int io_state_init_wlan(struct io_state *state, const char *wlan, const struct ether_addr *bssid_filter) { 275 | int err; 276 | 277 | strcpy(state->wlan_ifname, wlan); 278 | state->wlan_is_file = 0; 279 | 280 | if (!io_state_init_wlan_try_savefile(state)) { 281 | log_info("Using savefile instead of device"); 282 | return 0; 283 | } 284 | 285 | state->wlan_ifindex = if_nametoindex(state->wlan_ifname); 286 | if (!state->wlan_ifindex) { 287 | log_error("No such interface exists %s", state->wlan_ifname); 288 | return -ENOENT; 289 | } 290 | /* TODO we might instead open a new monitor interface instead */ 291 | err = link_down(state->wlan_ifindex); 292 | if (err < 0) { 293 | log_error("Could not set link down: %", state->wlan_ifname); 294 | return err; 295 | } 296 | if (!state->wlan_no_monitor_mode) /* if device is already in monitor mode */ 297 | err = set_monitor_mode(state->wlan_ifindex); 298 | if (err < 0) { 299 | log_error("Could not put device in monitor mode: %s", state->wlan_ifname); 300 | return err; 301 | } 302 | err = link_up(state->wlan_ifindex); 303 | if (err < 0) { 304 | log_error("Could set link up: %", state->wlan_ifname); 305 | return err; 306 | } 307 | state->wlan_fd = open_nonblocking_device(state->wlan_ifname, &state->wlan_handle, bssid_filter); 308 | if (state->wlan_fd < 0) { 309 | log_error("Could not open device: %s", state->wlan_ifname); 310 | return err; 311 | } 312 | err = link_ether_addr_get(state->wlan_ifname, &state->if_ether_addr); 313 | if (err < 0) { 314 | log_error("Could not get LLC address from %s", state->wlan_ifname); 315 | return err; 316 | } 317 | 318 | return 0; 319 | } 320 | 321 | static int io_state_init_host(struct io_state *state, const char *host) { 322 | int err; 323 | 324 | if (strlen(host) > 0) { 325 | strcpy(state->host_ifname, host); 326 | /* Host interface needs to have same ether_addr, to make active (!) monitor mode work */ 327 | state->host_fd = open_tun(state->host_ifname, &state->if_ether_addr); 328 | if ((err = state->host_fd) < 0) { 329 | log_error("Could not open device: %s", state->host_ifname); 330 | return err; 331 | } 332 | state->host_ifindex = if_nametoindex(state->host_ifname); 333 | if (!state->host_ifindex) { 334 | log_error("No such interface exists %s", state->host_ifname); 335 | return -ENOENT; 336 | } 337 | } else { 338 | log_debug("No host device given, start without host device"); 339 | } 340 | 341 | return 0; 342 | } 343 | 344 | int io_state_init(struct io_state *state, const char *wlan, const char *host, const struct ether_addr *bssid_filter) { 345 | int err; 346 | 347 | if ((err = io_state_init_wlan(state, wlan, bssid_filter))) 348 | return err; 349 | 350 | if ((err = io_state_init_host(state, host))) 351 | return err; 352 | 353 | return 0; 354 | } 355 | 356 | void io_state_free(struct io_state *state) { 357 | close(state->host_fd); 358 | pcap_close(state->wlan_handle); 359 | } 360 | 361 | int wlan_send(const struct io_state *state, const uint8_t *buf, int len) { 362 | int err; 363 | if (!state || !state->wlan_handle) 364 | return -EINVAL; 365 | err = pcap_inject(state->wlan_handle, buf, len); 366 | if (err < 0) { 367 | log_error("unable to inject packet (%s)", pcap_geterr(state->wlan_handle)); 368 | return err; 369 | } 370 | return 0; 371 | } 372 | 373 | int host_send(const struct io_state *state, const uint8_t *buf, int len) { 374 | if (!state || !state->host_fd) 375 | return -EINVAL; 376 | if (write(state->host_fd, buf, len) < 0) { 377 | return -errno; 378 | } 379 | return 0; 380 | } 381 | 382 | int host_recv(const struct io_state *state, uint8_t *buf, int *len) { 383 | long nread; 384 | if (!state || !state->host_fd) 385 | return -EINVAL; 386 | nread = read(state->host_fd, buf, *len); 387 | if (nread < 0) { 388 | if (errno != EWOULDBLOCK) 389 | log_error("tun: error reading from device"); 390 | return -errno; 391 | } 392 | *len = nread; 393 | return 0; 394 | } 395 | -------------------------------------------------------------------------------- /daemon/io.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #ifndef OWL_IO_H 21 | #define OWL_IO_H 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #ifdef __APPLE__ 29 | #include 30 | #else 31 | #include 32 | #endif 33 | 34 | struct io_state { 35 | pcap_t *wlan_handle; 36 | char wlan_ifname[PATH_MAX]; /* name of WLAN iface */ 37 | int wlan_ifindex; /* index of WLAN iface */ 38 | char host_ifname[IFNAMSIZ]; /* name of host iface */ 39 | int host_ifindex; /* index of host iface */ 40 | struct ether_addr if_ether_addr; /* MAC address of WLAN and host iface */ 41 | int wlan_fd; 42 | int host_fd; 43 | char *dumpfile; 44 | char wlan_no_monitor_mode; 45 | int wlan_is_file; 46 | }; 47 | 48 | int io_state_init(struct io_state *state, const char *wlan, const char *host, const struct ether_addr *bssid_filter); 49 | 50 | void io_state_free(struct io_state *state); 51 | 52 | int wlan_send(const struct io_state *state, const uint8_t *buf, int len); 53 | 54 | int host_send(const struct io_state *state, const uint8_t *buf, int len); 55 | 56 | int host_recv(const struct io_state *state, uint8_t *buf, int *len); 57 | 58 | #endif /* OWL_IO_H */ 59 | -------------------------------------------------------------------------------- /daemon/netutils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #ifndef OWL_NETUTILS_H_ 21 | #define OWL_NETUTILS_H_ 22 | 23 | #include 24 | #include 25 | #ifdef __APPLE__ 26 | #include 27 | #else 28 | #include 29 | #endif 30 | 31 | /** 32 | * Needs to be run once before netutils can be used (platform-dependent). 33 | * 34 | * For example, on Linux, sets up nl80211 socket and state. 35 | * 36 | * @return 0 on success, a negative value on failure 37 | */ 38 | int netutils_init(); 39 | 40 | /** 41 | * Clean up methods if netutils are no longer needed (platform-dependent) 42 | */ 43 | void netutils_cleanup(); 44 | 45 | int set_monitor_mode(int ifindex); 46 | 47 | int is_channel_available(int ifindex, int channel, bool *is_available); 48 | 49 | int set_channel(int ifindex, int channel); 50 | 51 | int link_up(int ifindex); 52 | 53 | int link_down(int ifindex); 54 | 55 | int link_ether_addr_get(const char *ifname, struct ether_addr *addr); 56 | 57 | int get_hostname(char *name, size_t len); 58 | 59 | int neighbor_add(int ifindex, const struct ether_addr *, const struct in6_addr *); 60 | 61 | int neighbor_remove(int ifindex, const struct in6_addr *); 62 | 63 | int neighbor_add_rfc4291(int ifindex, const struct ether_addr *); 64 | 65 | int neighbor_remove_rfc4291(int ifindex, const struct ether_addr *); 66 | 67 | void rfc4291_addr(const struct ether_addr *eth, struct in6_addr *in6); 68 | 69 | #endif /* OWL_NETUTILS_H_ */ 70 | -------------------------------------------------------------------------------- /daemon/owl.c: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "log.h" 29 | #include "core.h" 30 | 31 | #define DEFAULT_AWDL_DEVICE "awdl0" 32 | #define FAILED_DUMP "failed.pcap" 33 | 34 | static void daemonize() { 35 | pid_t pid; 36 | long x; 37 | 38 | /* Fork off the parent process */ 39 | pid = fork(); 40 | 41 | /* An error occurred */ 42 | if (pid < 0) 43 | exit(EXIT_FAILURE); 44 | 45 | /* Success: Let the parent terminate */ 46 | if (pid > 0) 47 | exit(EXIT_SUCCESS); 48 | 49 | /* On success: The child process becomes session leader */ 50 | if (setsid() < 0) 51 | exit(EXIT_FAILURE); 52 | 53 | /* Catch, ignore and handle signals */ 54 | /* TODO: Implement a working signal handler */ 55 | signal(SIGCHLD, SIG_IGN); 56 | signal(SIGHUP, SIG_IGN); 57 | 58 | /* Fork off for the second time*/ 59 | pid = fork(); 60 | 61 | /* An error occurred */ 62 | if (pid < 0) 63 | exit(EXIT_FAILURE); 64 | 65 | /* Success: Let the parent terminate */ 66 | if (pid > 0) 67 | exit(EXIT_SUCCESS); 68 | 69 | /* Set new file permissions */ 70 | umask(0); 71 | 72 | /* Change the working directory to the root directory */ 73 | /* or another appropriated directory */ 74 | chdir("/"); 75 | 76 | /* Close all open file descriptors */ 77 | for (x = sysconf(_SC_OPEN_MAX); x >= 0; x--) { 78 | close(x); 79 | } 80 | 81 | /* Open the log file */ 82 | openlog("owl", LOG_PID, LOG_DAEMON); 83 | } 84 | 85 | int main(int argc, char *argv[]) { 86 | int c; 87 | int daemon = 0; 88 | int dump = 0; 89 | int chan_num = 6; 90 | struct awdl_chan chan; 91 | int log_level = LOG_INFO; 92 | int filter_rssi = 1; 93 | int no_monitor_mode = 0; 94 | 95 | char wlan[PATH_MAX] = ""; 96 | char host[IFNAMSIZ] = DEFAULT_AWDL_DEVICE; 97 | 98 | struct ev_loop *loop; 99 | 100 | struct daemon_state state; 101 | 102 | while ((c = getopt(argc, argv, "Dc:dvi:h:a:t:fN")) != -1) { 103 | switch (c) { 104 | case 'D': 105 | daemon = 1; 106 | break; 107 | case 'c': 108 | chan_num = atoi(optarg); 109 | break; 110 | case 'd': 111 | dump = 1; 112 | break; 113 | case 'f': 114 | filter_rssi = 0; 115 | break; 116 | case 'v': 117 | if (log_level < LOG_TRACE) 118 | log_level++; /* increase log level with every occurence of option */ 119 | break; 120 | case 'i': 121 | strcpy(wlan, optarg); 122 | break; 123 | case 'h': 124 | strcpy(host, optarg); 125 | break; 126 | case 'N': 127 | no_monitor_mode = 1; 128 | break; 129 | case '?': 130 | if (optopt == 'i') 131 | fprintf(stderr, "Option -%c needs to specify a wireless interface.\n", optopt); 132 | return EXIT_FAILURE; 133 | default: 134 | abort(); 135 | } 136 | } 137 | 138 | log_set_level(log_level); 139 | 140 | printf(" .oOXWMMMMWXOx:\n" 141 | " .oOOOx:'''''''''''':OOOx:\n" 142 | " oXOo' ........ ':OXx.\n" 143 | " .oOOO''''''''''OOOo.\n" 144 | " oXOo' 'oOO:\n" 145 | " :oOOOOXXXXOOOOo:.\n" 146 | " oXO:' ':OXo\n" 147 | " .:xOXXXXXXOx:.\n" 148 | " .xXMMMMMMMMMMMMMMMMXx.\n" 149 | " 'XWWWWWWMMMMMMMMMMMMMMMMMMMMMMWWWWWWX'\n" 150 | " oWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMWo\n" 151 | " OMMMMMMWWMMMMMMMMMMMMMMWWWMMMMMO\n" 152 | " OMMWx' 'xWMMMMWx' 'oXMMO\n" 153 | " :MW: oMMx 'WM:\n" 154 | " XM' .xOOo. :o .xOOo. WX\n" 155 | " WX :MMMMMX :MMMMMX xW\n" 156 | " XW 'WMMMMX .xx. 'WMMMWX XX\n" 157 | " 'Wx 'xWMx' OMMO 'xWMx' xM'\n" 158 | " 'XX: 'XX' :XX'\n" 159 | " 'xXOx:..................:xXWx'\n" 160 | " 'xXMMMMMMMMMMMMMMMMMMWO'\n" 161 | "\n" 162 | " Open Wireless Link\n" 163 | "\n" 164 | " https://owlink.org\n" 165 | "\n"); 166 | 167 | if (daemon) 168 | daemonize(); 169 | 170 | switch (chan_num) { 171 | case 6: 172 | chan = CHAN_OPCLASS_6; 173 | break; 174 | case 44: 175 | chan = CHAN_OPCLASS_44; 176 | break; 177 | case 149: 178 | chan = CHAN_OPCLASS_149; 179 | break; 180 | default: 181 | log_error("Unsupported channel %d (use 6, 44, or 149)", chan_num); 182 | return EXIT_FAILURE; 183 | } 184 | 185 | if (!*wlan) { 186 | log_error("No interface specified"); 187 | return EXIT_FAILURE; 188 | } 189 | 190 | state.io.wlan_no_monitor_mode = no_monitor_mode; 191 | 192 | if (awdl_init(&state, wlan, host, chan, dump ? FAILED_DUMP : 0) < 0) { 193 | log_error("could not initialize core"); 194 | return EXIT_FAILURE; 195 | } 196 | state.awdl_state.filter_rssi = filter_rssi; 197 | 198 | if (state.io.wlan_ifindex) 199 | log_info("WLAN device: %s (addr %s)", state.io.wlan_ifname, ether_ntoa(&state.io.if_ether_addr)); 200 | if (state.io.host_ifindex) 201 | log_info("Host device: %s", state.io.host_ifname); 202 | 203 | loop = EV_DEFAULT; 204 | 205 | awdl_schedule(loop, &state); 206 | 207 | ev_run(loop, 0); 208 | 209 | awdl_free(&state); 210 | 211 | return EXIT_SUCCESS; 212 | } 213 | -------------------------------------------------------------------------------- /resources/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seemoo-lab/owl/8e4e840b212ae5a09a8a99484be3ab18bad22fa7/resources/overview.png -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(awdl "") 2 | 3 | target_sources(awdl PRIVATE 4 | log.c 5 | log.h 6 | state.c 7 | state.h 8 | election.c 9 | election.h 10 | sync.c 11 | sync.h 12 | channel.c 13 | channel.h 14 | schedule.c 15 | schedule.h 16 | tx.c 17 | tx.h 18 | rx.c 19 | rx.h 20 | frame.c 21 | frame.h 22 | crc32.c 23 | crc32.h 24 | wire.c 25 | wire.h 26 | peers.c 27 | peers.h 28 | version.c 29 | version.h 30 | hashmap.c 31 | hashmap.h 32 | siphash24.c 33 | siphash24.h 34 | circular_buffer.c 35 | circular_buffer.h 36 | ) 37 | 38 | target_include_directories(awdl PRIVATE ${CMAKE_SOURCE_DIR}/radiotap) 39 | 40 | target_link_libraries(awdl radiotap) 41 | -------------------------------------------------------------------------------- /src/channel.c: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #include "channel.h" 21 | #include "ieee80211.h" 22 | 23 | void awdl_chanseq_init(struct awdl_chan *seq) { 24 | for (int i = 0; i < AWDL_CHANSEQ_LENGTH; i++, seq++) { 25 | if (i < 8) 26 | *seq = CHAN_OPCLASS_149; 27 | else 28 | *seq = CHAN_OPCLASS_6; 29 | } 30 | } 31 | 32 | void awdl_chanseq_init_idle(struct awdl_chan *seq) { 33 | for (int i = 0; i < AWDL_CHANSEQ_LENGTH; i++, seq++) { 34 | switch (i) { 35 | case 8: 36 | *seq = CHAN_OPCLASS_6; 37 | break; 38 | case 0: 39 | case 9: 40 | case 10: 41 | *seq = CHAN_OPCLASS_149; 42 | break; 43 | default: 44 | *seq = CHAN_NULL; 45 | break; 46 | } 47 | } 48 | } 49 | 50 | void awdl_chanseq_init_static(struct awdl_chan *seq, const struct awdl_chan *chan) { 51 | for (int i = 0; i < AWDL_CHANSEQ_LENGTH; i++, seq++) { 52 | *seq = *chan; 53 | } 54 | } 55 | 56 | uint8_t awdl_chan_num(struct awdl_chan chan, enum awdl_chan_encoding enc) { 57 | switch (enc) { 58 | case AWDL_CHAN_ENC_SIMPLE: 59 | return chan.simple.chan_num; 60 | case AWDL_CHAN_ENC_LEGACY: 61 | return chan.legacy.chan_num; 62 | case AWDL_CHAN_ENC_OPCLASS: 63 | return chan.opclass.chan_num; 64 | default: 65 | return 0; /* unknown encoding */ 66 | } 67 | } 68 | 69 | int awdl_chan_encoding_size(enum awdl_chan_encoding enc) { 70 | switch (enc) { 71 | case AWDL_CHAN_ENC_SIMPLE: 72 | return 1; 73 | case AWDL_CHAN_ENC_LEGACY: 74 | case AWDL_CHAN_ENC_OPCLASS: 75 | return 2; 76 | default: 77 | return -1; /* unknown encoding */ 78 | } 79 | } 80 | 81 | /* adapted from iw/util.c */ 82 | int ieee80211_channel_to_frequency(int chan) { 83 | /* see 802.11 17.3.8.3.2 and Annex J 84 | * there are overlapping channel numbers in 5GHz and 2GHz bands */ 85 | if (chan <= 0) 86 | return 0; /* not supported */ 87 | 88 | /* 2 GHz band */ 89 | if (chan == 14) 90 | return 2484; 91 | else if (chan < 14) 92 | return 2407 + chan * 5; 93 | 94 | /* 5 GHz band */ 95 | if (chan < 32) 96 | return 0; /* not supported */ 97 | 98 | if (chan >= 182 && chan <= 196) 99 | return 4000 + chan * 5; 100 | else 101 | return 5000 + chan * 5; 102 | 103 | } 104 | 105 | /* from iw/util.c */ 106 | int ieee80211_frequency_to_channel(int freq) { 107 | /* see 802.11-2007 17.3.8.3.2 and Annex J */ 108 | if (freq == 2484) 109 | return 14; 110 | else if (freq < 2484) 111 | return (freq - 2407) / 5; 112 | else if (freq >= 4910 && freq <= 4980) 113 | return (freq - 4000) / 5; 114 | else if (freq <= 45000) /* DMG band lower limit */ 115 | return (freq - 5000) / 5; 116 | else if (freq >= 58320 && freq <= 64800) 117 | return (freq - 56160) / 2160; 118 | else 119 | return 0; 120 | } 121 | -------------------------------------------------------------------------------- /src/channel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #ifndef AWDL_CHANNEL_H_ 21 | #define AWDL_CHANNEL_H_ 22 | 23 | #include 24 | 25 | #define AWDL_CHANSEQ_LENGTH 16 26 | 27 | enum awdl_chan_encoding { 28 | AWDL_CHAN_ENC_SIMPLE = 0, 29 | AWDL_CHAN_ENC_LEGACY = 1, 30 | AWDL_CHAN_ENC_OPCLASS = 3, 31 | }; 32 | 33 | struct awdl_chan { 34 | union { 35 | uint8_t val[2]; 36 | struct { 37 | uint8_t chan_num; 38 | } simple; 39 | struct { 40 | uint8_t flags; 41 | uint8_t chan_num; 42 | } legacy; 43 | struct { 44 | uint8_t chan_num; 45 | uint8_t opclass; 46 | } opclass; 47 | }; 48 | }; 49 | 50 | #define CHAN_NULL (struct awdl_chan) { { { 0, 0x00 } } } 51 | #define CHAN_OPCLASS_6 (struct awdl_chan) { { { 6, 0x51 } } } 52 | #define CHAN_OPCLASS_44 (struct awdl_chan) { { { 44, 0x80 } } } 53 | #define CHAN_OPCLASS_149 (struct awdl_chan) { { { 149, 0x80 } } } 54 | 55 | uint8_t awdl_chan_num(struct awdl_chan chan, enum awdl_chan_encoding); 56 | 57 | int awdl_chan_encoding_size(enum awdl_chan_encoding); 58 | 59 | struct awdl_channel_state { 60 | enum awdl_chan_encoding enc; 61 | struct awdl_chan sequence[AWDL_CHANSEQ_LENGTH]; 62 | struct awdl_chan master; 63 | struct awdl_chan current; 64 | }; 65 | 66 | void awdl_chanseq_init(struct awdl_chan *seq); 67 | 68 | void awdl_chanseq_init_idle(struct awdl_chan *seq); 69 | 70 | void awdl_chanseq_init_static(struct awdl_chan *seq, const struct awdl_chan *chan); 71 | 72 | #endif /* AWDL_CHANNEL_H_ */ 73 | -------------------------------------------------------------------------------- /src/circular_buffer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "circular_buffer.h" 7 | 8 | // The definition of our circular buffer structure is hidden from the user 9 | struct circular_buf { 10 | void **buffer; 11 | size_t head; 12 | size_t tail; 13 | size_t max; //of the buffer 14 | int full; 15 | }; 16 | 17 | static void advance_pointer(cbuf_handle_t cbuf) 18 | { 19 | assert(cbuf); 20 | 21 | if(cbuf->full) 22 | { 23 | cbuf->tail = (cbuf->tail + 1) % cbuf->max; 24 | } 25 | 26 | cbuf->head = (cbuf->head + 1) % cbuf->max; 27 | 28 | // We mark full because we will advance tail on the next time around 29 | cbuf->full = (cbuf->head == cbuf->tail); 30 | } 31 | 32 | static void retreat_pointer(cbuf_handle_t cbuf) 33 | { 34 | assert(cbuf); 35 | 36 | cbuf->full = 0; 37 | cbuf->tail = (cbuf->tail + 1) % cbuf->max; 38 | } 39 | 40 | cbuf_handle_t circular_buf_init(size_t size) 41 | { 42 | assert(size); 43 | 44 | cbuf_handle_t cbuf = malloc(sizeof(struct circular_buf)); 45 | assert(cbuf); 46 | 47 | cbuf->buffer = malloc(size * sizeof(void*)); 48 | cbuf->max = size; 49 | circular_buf_reset(cbuf); 50 | 51 | assert(circular_buf_empty(cbuf)); 52 | 53 | return cbuf; 54 | } 55 | 56 | void circular_buf_free(cbuf_handle_t cbuf) 57 | { 58 | assert(cbuf); 59 | assert(cbuf->buffer); 60 | free(cbuf->buffer); 61 | free(cbuf); 62 | } 63 | 64 | void circular_buf_reset(cbuf_handle_t cbuf) 65 | { 66 | assert(cbuf); 67 | 68 | cbuf->head = 0; 69 | cbuf->tail = 0; 70 | cbuf->full = 0; 71 | } 72 | 73 | size_t circular_buf_size(cbuf_handle_t cbuf) 74 | { 75 | assert(cbuf); 76 | 77 | size_t size = cbuf->max; 78 | 79 | if(!cbuf->full) 80 | { 81 | if(cbuf->head >= cbuf->tail) 82 | { 83 | size = (cbuf->head - cbuf->tail); 84 | } 85 | else 86 | { 87 | size = (cbuf->max + cbuf->head - cbuf->tail); 88 | } 89 | 90 | } 91 | 92 | return size; 93 | } 94 | 95 | size_t circular_buf_capacity(cbuf_handle_t cbuf) 96 | { 97 | assert(cbuf); 98 | 99 | return cbuf->max; 100 | } 101 | 102 | void circular_buf_put(cbuf_handle_t cbuf, void *data) 103 | { 104 | assert(cbuf && cbuf->buffer); 105 | 106 | cbuf->buffer[cbuf->head] = data; 107 | 108 | advance_pointer(cbuf); 109 | } 110 | 111 | int circular_buf_put2(cbuf_handle_t cbuf, void *data) 112 | { 113 | int r = -1; 114 | 115 | assert(cbuf && cbuf->buffer); 116 | 117 | if(!circular_buf_full(cbuf)) 118 | { 119 | cbuf->buffer[cbuf->head] = data; 120 | advance_pointer(cbuf); 121 | r = 0; 122 | } 123 | 124 | return r; 125 | } 126 | 127 | int circular_buf_get(cbuf_handle_t cbuf, void **data, int peek) 128 | { 129 | assert(cbuf && cbuf->buffer); 130 | 131 | int r = -1; 132 | 133 | if(!circular_buf_empty(cbuf)) 134 | { 135 | if (data) 136 | *data = cbuf->buffer[cbuf->tail]; 137 | if (!peek) 138 | retreat_pointer(cbuf); 139 | 140 | r = 0; 141 | } 142 | 143 | return r; 144 | } 145 | 146 | int circular_buf_empty(cbuf_handle_t cbuf) 147 | { 148 | assert(cbuf); 149 | 150 | return (!cbuf->full && (cbuf->head == cbuf->tail)); 151 | } 152 | 153 | int circular_buf_full(cbuf_handle_t cbuf) 154 | { 155 | assert(cbuf); 156 | 157 | return cbuf->full; 158 | } 159 | -------------------------------------------------------------------------------- /src/circular_buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef CIRCULAR_BUFFER_H_ 2 | #define CIRCULAR_BUFFER_H_ 3 | 4 | /// Handle type, the way users interact with the API 5 | typedef struct circular_buf *cbuf_handle_t; 6 | 7 | /// Pass in a size, returns a circular buffer handle 8 | /// Requires: size > 0 9 | /// Ensures: cbuf has been created and is returned in an empty state 10 | cbuf_handle_t circular_buf_init(size_t size); 11 | 12 | /// Free a circular buffer structure 13 | /// Requires: cbuf is valid and created by circular_buf_init 14 | void circular_buf_free(cbuf_handle_t cbuf); 15 | 16 | /// Reset the circular buffer to empty, head == tail. Data not cleared 17 | /// Requires: cbuf is valid and created by circular_buf_init 18 | void circular_buf_reset(cbuf_handle_t cbuf); 19 | 20 | /// Put version 1 continues to add data if the buffer is full 21 | /// Old data is overwritten 22 | /// Requires: cbuf is valid and created by circular_buf_init 23 | void circular_buf_put(cbuf_handle_t cbuf, void *data); 24 | 25 | /// Put Version 2 rejects new data if the buffer is full 26 | /// Requires: cbuf is valid and created by circular_buf_init 27 | /// Returns 0 on success, -1 if buffer is full 28 | int circular_buf_put2(cbuf_handle_t cbuf, void *data); 29 | 30 | /// Retrieve a value from the buffer 31 | /// Requires: cbuf is valid and created by circular_buf_init 32 | /// Returns 0 on success, -1 if the buffer is empty 33 | int circular_buf_get(cbuf_handle_t cbuf, void **data, int peek); 34 | 35 | /// CHecks if the buffer is empty 36 | /// Requires: cbuf is valid and created by circular_buf_init 37 | /// Returns true if the buffer is empty 38 | int circular_buf_empty(cbuf_handle_t cbuf); 39 | 40 | /// Checks if the buffer is full 41 | /// Requires: cbuf is valid and created by circular_buf_init 42 | /// Returns true if the buffer is full 43 | int circular_buf_full(cbuf_handle_t cbuf); 44 | 45 | /// Check the capacity of the buffer 46 | /// Requires: cbuf is valid and created by circular_buf_init 47 | /// Returns the maximum capacity of the buffer 48 | size_t circular_buf_capacity(cbuf_handle_t cbuf); 49 | 50 | /// Check the number of elements stored in the buffer 51 | /// Requires: cbuf is valid and created by circular_buf_init 52 | /// Returns the current number of elements in the buffer 53 | size_t circular_buf_size(cbuf_handle_t cbuf); 54 | 55 | #endif /* CIRCULAR_BUFFER_H_ */ 56 | -------------------------------------------------------------------------------- /src/crc32.c: -------------------------------------------------------------------------------- 1 | #include "crc32.h" 2 | 3 | /* crc32 calculation */ 4 | const uint32_t crc32_tab[] = { 5 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 6 | 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 7 | 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 8 | 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 9 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 10 | 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 11 | 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 12 | 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 13 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 14 | 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 15 | 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 16 | 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 17 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 18 | 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 19 | 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 20 | 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 21 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 22 | 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 23 | 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 24 | 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 25 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 26 | 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 27 | 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 28 | 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 29 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 30 | 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 31 | 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 32 | 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 33 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 34 | 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 35 | 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 36 | 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 37 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 38 | 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 39 | 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 40 | 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 41 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 42 | 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 43 | 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 44 | 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 45 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 46 | 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 47 | 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 48 | }; 49 | 50 | uint32_t crc32(const void *buf, unsigned long size) { 51 | const uint8_t *p = buf; 52 | uint32_t crc; 53 | crc = ~0u; 54 | while (size--) 55 | crc = crc32_tab[(crc ^ *p++) & 0xff] ^ (crc >> 8); 56 | return crc ^ ~0u; 57 | } 58 | -------------------------------------------------------------------------------- /src/crc32.h: -------------------------------------------------------------------------------- 1 | #ifndef CRC32_H_ 2 | #define CRC32_H_ 3 | 4 | #include 5 | 6 | uint32_t crc32(const void *buf, unsigned long size); 7 | 8 | #endif /* CRC32_H_ */ 9 | -------------------------------------------------------------------------------- /src/election.c: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "election.h" 24 | #include "peers.h" 25 | #include "log.h" 26 | 27 | static inline int compare(uint32_t a, uint32_t b) { 28 | return (a < b) ? -1 : (a > b); 29 | } 30 | 31 | int compare_ether_addr(const struct ether_addr *a, const struct ether_addr *b) { 32 | return memcmp(a, b, sizeof(struct ether_addr)); 33 | } 34 | 35 | int awdl_election_is_sync_master(const struct awdl_election_state *state, const struct ether_addr *addr) { 36 | return !compare_ether_addr(&state->sync_addr, addr); 37 | } 38 | 39 | static void awdl_election_reset_metric(struct awdl_election_state *state) { 40 | state->self_counter = AWDL_ELECTION_COUNTER_INIT; 41 | state->self_metric = AWDL_ELECTION_METRIC_INIT; 42 | } 43 | 44 | static void awdl_election_reset_self(struct awdl_election_state *state) { 45 | state->height = 0; 46 | state->master_addr = state->self_addr; 47 | state->sync_addr = state->self_addr; 48 | state->master_metric = state->self_metric; 49 | state->master_counter = state->self_counter; 50 | } 51 | 52 | void awdl_election_state_init(struct awdl_election_state *state, const struct ether_addr *self) { 53 | state->master_addr = *self; 54 | state->sync_addr = *self; 55 | state->self_addr = *self; 56 | awdl_election_reset_metric(state); 57 | awdl_election_reset_self(state); 58 | } 59 | 60 | static int awdl_election_compare_master(const struct awdl_election_state *a, const struct awdl_election_state *b) { 61 | int result = compare(a->master_counter, b->master_counter); 62 | if (!result) 63 | result = compare(a->master_metric, b->master_metric); 64 | return result; 65 | } 66 | 67 | void awdl_election_run(struct awdl_election_state *state, const struct awdl_peer_state *peers) { 68 | struct awdl_peer *peer; 69 | struct ether_addr old_top_master = state->master_addr; 70 | struct ether_addr old_sync_master = state->sync_addr; 71 | struct awdl_election_state *master_state = state; 72 | awdl_peers_it_t it = awdl_peers_it_new(peers->peers); 73 | 74 | awdl_election_reset_self(state); 75 | 76 | /* probably not fully correct */ 77 | while (awdl_peers_it_next(it, &peer) == PEERS_OK) { 78 | int cmp_metric; 79 | struct awdl_election_state *peer_state = &peer->election; 80 | if (!peer->is_valid) 81 | continue; /* reject: not a valid peer */ 82 | if (peer_state->height + 1 > AWDL_ELECTION_TREE_MAX_HEIGHT) { 83 | log_debug("Ignore peer %s because sync tree would get too large (%u, max %u)", 84 | ether_ntoa(&peer_state->self_addr), peer_state->height + 1, AWDL_ELECTION_TREE_MAX_HEIGHT); 85 | continue; /* reject: tree would get too large if accepted as sync master */ 86 | } 87 | if (awdl_election_is_sync_master(peer_state, &state->self_addr)) 88 | continue; /* reject: do not allow cycles in sync tree */ 89 | cmp_metric = awdl_election_compare_master(peer_state, master_state); 90 | if (cmp_metric < 0) { 91 | continue; /* reject: lower top master metric */ 92 | } else if (cmp_metric == 0) { 93 | /* if metric is same, compare distance to master */ 94 | if (peer_state->height > master_state->height) { 95 | continue; /* reject: do not increase length of sync tree */ 96 | } else if (peer_state->height == master_state->height) { 97 | /* if height is same, need tie breaker */ 98 | if (compare_ether_addr(&peer_state->self_addr, &master_state->self_addr) <= 0) 99 | continue; /* reject: peer has smaller address */ 100 | } 101 | } 102 | /* accept: otherwise */ 103 | master_state = peer_state; 104 | } 105 | 106 | if (state != master_state) { /* adopt new master */ 107 | state->master_addr = master_state->master_addr; 108 | state->sync_addr = master_state->self_addr; 109 | state->master_metric = master_state->master_metric; 110 | state->master_counter = master_state->master_counter; 111 | state->height = master_state->height + 1; 112 | } 113 | 114 | if (compare_ether_addr(&old_top_master, &state->master_addr) || 115 | compare_ether_addr(&old_sync_master, &state->sync_addr)) { 116 | char tree[256]; 117 | awdl_election_tree_print(state, tree, sizeof(tree)); 118 | log_debug("new election tree: %s", tree); 119 | } 120 | } 121 | 122 | int awdl_election_tree_print(const struct awdl_election_state *state, char *str, int len) { 123 | char *cur = str, *const end = str + len; 124 | cur += snprintf(cur, cur < end ? end - cur: 0, "%s", ether_ntoa(&state->self_addr)); 125 | if (state->height > 0) 126 | cur += snprintf(cur, cur < end ? end - cur : 0, " -> %s", ether_ntoa(&state->sync_addr)); 127 | if (state->height > 1) { 128 | cur += snprintf(cur, cur < end ? end - cur : 0, " "); 129 | for (uint32_t i = 1; i < state->height; i++) 130 | cur += snprintf(cur, cur < end ? end - cur : 0, "-"); /* one dash for every intermediate hop */ 131 | cur += snprintf(cur, cur < end ? end - cur : 0, "> %s", ether_ntoa(&state->master_addr)); 132 | } 133 | cur += snprintf(cur, cur < end ? end - cur : 0, " (met %u, ctr %u)", state->master_metric, state->master_counter); 134 | return cur - str; 135 | } 136 | -------------------------------------------------------------------------------- /src/election.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #ifndef AWDL_ELECTION_H_ 21 | #define AWDL_ELECTION_H_ 22 | 23 | #include "ieee80211.h" 24 | 25 | #define AWDL_ELECTION_TREE_MAX_HEIGHT 10 /* arbitrary limit */ 26 | #define AWDL_ELECTION_METRIC_INIT 60 27 | #define AWDL_ELECTION_COUNTER_INIT 0 28 | 29 | struct awdl_peer_state; 30 | 31 | struct awdl_election_state { 32 | struct ether_addr master_addr; 33 | struct ether_addr sync_addr; 34 | struct ether_addr self_addr; 35 | uint32_t height; 36 | uint32_t master_metric; 37 | uint32_t self_metric; 38 | uint32_t master_counter; 39 | uint32_t self_counter; 40 | }; 41 | 42 | int awdl_election_is_sync_master(const struct awdl_election_state *state, const struct ether_addr *addr); 43 | 44 | void awdl_election_state_init(struct awdl_election_state *state, const struct ether_addr *self); 45 | 46 | void awdl_election_run(struct awdl_election_state *state, const struct awdl_peer_state *peers); 47 | 48 | int awdl_election_tree_print(const struct awdl_election_state *state, char *str, int len); 49 | 50 | /* Util functions */ 51 | int compare_ether_addr(const struct ether_addr *a, const struct ether_addr *b); 52 | 53 | #endif /* AWDL_ELECTION_H_ */ 54 | -------------------------------------------------------------------------------- /src/frame.c: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #include "frame.h" 21 | 22 | const char *awdl_frame_as_str(uint8_t type) { 23 | switch (type) { 24 | case AWDL_ACTION_PSF: 25 | return "PSF"; 26 | case AWDL_ACTION_MIF: 27 | return "MIF"; 28 | default: 29 | return "Unknown"; 30 | } 31 | } 32 | 33 | const char *awdl_tlv_as_str(uint8_t type) { 34 | switch (type) { 35 | case AWDL_SSTH_REQUEST_TLV: 36 | return "SSTH Request"; 37 | case AWDL_SERVICE_REQUEST_TLV: 38 | return "Service Request"; 39 | case AWDL_SERVICE_RESPONSE_TLV: 40 | return "Service Response"; 41 | case AWDL_SYNCHRONIZATON_PARAMETERS_TLV: 42 | return "Synchronization Parameters"; 43 | case AWDL_ELECTION_PARAMETERS_TLV: 44 | return "Election Parameters"; 45 | case AWDL_SERVICE_PARAMETERS_TLV: 46 | return "Service Parameters"; 47 | case AWDL_ENHANCED_DATA_RATE_CAPABILITIES_TLV: 48 | return "HT Capabilities"; 49 | case AWDL_ENHANCED_DATA_RATE_OPERATION_TLV: 50 | return "HT Operation"; 51 | case AWDL_INFRA_TLV: 52 | return "Infra"; 53 | case AWDL_INVITE_TLV: 54 | return "Invite"; 55 | case AWDL_DBG_STRING_TLV: 56 | return "Debug String"; 57 | case AWDL_DATA_PATH_STATE_TLV: 58 | return "Data Path State"; 59 | case AWDL_ENCAPSULATED_IP_TLV: 60 | return "Encapsulated IP"; 61 | case AWDL_DATAPATH_DEBUG_PACKET_LIVE_TLV: 62 | return "Datapath Debug Packet Live"; 63 | case AWDL_DATAPATH_DEBUG_AF_LIVE_TLV: 64 | return "Datapath Debug AF Live"; 65 | case AWDL_ARPA_TLV: 66 | return "Arpa"; 67 | case AWDL_IEEE80211_CNTNR_TLV: 68 | return "VHT Capabilities"; 69 | case AWDL_CHAN_SEQ_TLV: 70 | return "Channel Sequence"; 71 | case AWDL_SYNCTREE_TLV: 72 | return "Synchronization Tree"; 73 | case AWDL_VERSION_TLV: 74 | return "Version"; 75 | case AWDL_BLOOM_FILTER_TLV: 76 | return "Bloom Filter"; 77 | case AWDL_NAN_SYNC_TLV: 78 | return "NAN Sync"; 79 | case AWDL_ELECTION_PARAMETERS_V2_TLV: 80 | return "Election Parameters v2"; 81 | default: 82 | return "Unknown"; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/frame.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #ifndef AWDL_FRAME_H_ 21 | #define AWDL_FRAME_H_ 22 | 23 | #include 24 | 25 | #include "ieee80211.h" 26 | 27 | #define AWDL_LLC_PROTOCOL_ID 0x0800 28 | 29 | #define AWDL_OUI (struct oui){{ 0x00, 0x17, 0xf2 }} 30 | #define AWDL_BSSID (struct ether_addr){{ 0x00, 0x25, 0x00, 0xff, 0x94, 0x73 }} 31 | 32 | #define IEEE80211_VENDOR_SPECIFIC 127 33 | #define AWDL_VERSION_COMPAT awdl_version(1, 0) 34 | #define AWDL_TYPE 8 35 | 36 | struct awdl_data { 37 | uint16_t head; /* AWDL_DATA_HEAD */ 38 | uint16_t seq; 39 | uint16_t pad; /* AWDL_DATA_PAD */ 40 | uint16_t ethertype; 41 | } __attribute__((__packed__)); 42 | 43 | struct awdl_action { 44 | uint8_t category; /* 127 - vendor-specific */ 45 | struct oui oui; 46 | uint8_t type; 47 | uint8_t version; 48 | uint8_t subtype; /* awdl_frame_types */ 49 | uint8_t reserved; 50 | uint32_t phy_tx; 51 | uint32_t target_tx; 52 | } __attribute__((__packed__)); 53 | 54 | enum awdl_action_type { 55 | AWDL_ACTION_PSF = 0, 56 | AWDL_ACTION_MIF = 3, 57 | }; 58 | 59 | const char *awdl_frame_as_str(uint8_t type); 60 | 61 | /* AWDL TLV type values */ 62 | enum awdl_tlvs { 63 | AWDL_SSTH_REQUEST_TLV = 0, /* assumed deprecated */ 64 | AWDL_SERVICE_REQUEST_TLV = 1, /* assumed deprecated */ 65 | AWDL_SERVICE_RESPONSE_TLV = 2, 66 | AWDL_SYNCHRONIZATON_PARAMETERS_TLV = 4, 67 | AWDL_ELECTION_PARAMETERS_TLV = 5, 68 | AWDL_SERVICE_PARAMETERS_TLV = 6, 69 | AWDL_ENHANCED_DATA_RATE_CAPABILITIES_TLV = 7, 70 | AWDL_ENHANCED_DATA_RATE_OPERATION_TLV = 8, /* assumed deprecated */ 71 | AWDL_INFRA_TLV = 9, /* assumed deprecated */ 72 | AWDL_INVITE_TLV = 10, /* assumed deprecated */ 73 | AWDL_DBG_STRING_TLV = 11, /* assumed deprecated */ 74 | AWDL_DATA_PATH_STATE_TLV = 12, 75 | AWDL_ENCAPSULATED_IP_TLV = 13, /* assumed deprecated */ 76 | AWDL_DATAPATH_DEBUG_PACKET_LIVE_TLV = 14, /* assumed deprecated */ 77 | AWDL_DATAPATH_DEBUG_AF_LIVE_TLV = 15, /* assumed deprecated */ 78 | AWDL_ARPA_TLV = 16, 79 | AWDL_IEEE80211_CNTNR_TLV = 17, 80 | AWDL_CHAN_SEQ_TLV = 18, 81 | AWDL_SYNCTREE_TLV = 20, 82 | AWDL_VERSION_TLV = 21, 83 | AWDL_BLOOM_FILTER_TLV = 22, 84 | AWDL_NAN_SYNC_TLV = 23, 85 | AWDL_ELECTION_PARAMETERS_V2_TLV = 24, 86 | }; 87 | 88 | struct tl { 89 | uint8_t type; 90 | uint16_t length; 91 | } __attribute__((__packed__)); 92 | 93 | struct awdl_chanseq { 94 | uint8_t count; 95 | uint8_t encoding; 96 | uint8_t duplicate_count; 97 | uint8_t step_count; 98 | uint16_t fill_channel; 99 | } __attribute__((__packed__)); 100 | 101 | 102 | struct awdl_sync_params_tlv { 103 | uint8_t type; 104 | uint16_t length; 105 | uint8_t next_aw_channel; 106 | uint16_t tx_down_counter; 107 | uint8_t master_channel; 108 | uint8_t guard_time; 109 | uint16_t aw_period; /* AW period in TUs */ 110 | uint16_t af_period; /* how often action frames are sent out in TUs */ 111 | uint16_t flags; 112 | uint16_t aw_ext_length; /* length of an extended AW in TUs */ 113 | uint16_t aw_com_length; /* length of a regular AW in TUs */ 114 | uint16_t remaining_aw_length; 115 | uint8_t min_ext; 116 | uint8_t max_ext_multicast; 117 | uint8_t max_ext_unicast; 118 | uint8_t max_ext_af; 119 | struct ether_addr master_addr; 120 | uint8_t presence_mode; 121 | uint8_t reserved; 122 | uint16_t next_aw_seq; 123 | uint16_t ap_alignment; 124 | /* struct awdl_chanseq chanseq; */ 125 | /* uint8_t pad[2]; */ 126 | } __attribute__((__packed__)); 127 | 128 | struct awdl_chanseq_tlv { 129 | uint8_t type; 130 | uint16_t length; 131 | /* struct awdl_chanseq chanseq; */ 132 | /* uint8_t pad[3]; */ 133 | } __attribute__((__packed__)); 134 | 135 | /* AWDL election parameters */ 136 | struct awdl_election_params_tlv { 137 | uint8_t type; 138 | uint16_t length; 139 | uint8_t flags; 140 | uint16_t id; 141 | uint8_t distancetop; 142 | uint8_t unknown; 143 | struct ether_addr top_master_addr; 144 | uint32_t top_master_metric; 145 | uint32_t self_metric; 146 | uint8_t pad[2]; 147 | } __attribute__((__packed__)); 148 | 149 | struct awdl_election_params_v2_tlv { 150 | uint8_t type; 151 | uint16_t length; 152 | struct ether_addr master_addr; /* currently elected master */ 153 | struct ether_addr sync_addr; /* this is _probably_ the node we currently sync to */ 154 | uint32_t master_counter; /* 'self_counter' of currently elected master */ 155 | uint32_t distance_to_master; 156 | uint32_t master_metric; 157 | uint32_t self_metric; 158 | uint32_t unknown; /* 0 */ 159 | uint32_t reserved; /* 0 */ 160 | uint32_t self_counter; /* is incremented by 1 while node is selected as master every PI (3.14) seconds */ 161 | } __attribute__((__packed__)); 162 | 163 | struct awdl_sync_tree_tlv { 164 | uint8_t type; 165 | uint16_t length; 166 | struct ether_addr tree[1]; 167 | } __attribute__((__packed__)); 168 | 169 | struct awdl_service_params_tlv { 170 | uint8_t type; 171 | uint16_t length; 172 | unsigned char unknown[3]; 173 | uint16_t sui; 174 | uint32_t bitmask; 175 | } __attribute__((__packed__)); 176 | 177 | struct awdl_ht_capabilities_tlv { 178 | uint8_t type; 179 | uint16_t length; 180 | uint16_t unknown; 181 | uint16_t ht_capabilities; 182 | uint8_t ampdu_params; 183 | uint8_t rx_mcs; 184 | uint16_t unknown2; 185 | } __attribute__((__packed__)); 186 | 187 | enum awdl_data_path_state_flags { 188 | AWDL_DATA_PATH_FLAG_COUNTRY_CODE = 0x0100, 189 | AWDL_DATA_PATH_FLAG_SOCIAL_CHANNEL_MAP = 0x0200, 190 | AWDL_DATA_PATH_FLAG_INFRA_INFO = 0x0001, 191 | AWDL_DATA_PATH_FLAG_INFRA_ADDRESS = 0x0002, 192 | AWDL_DATA_PATH_FLAG_AWDL_ADDRESS = 0x0004, 193 | AWDL_DATA_PATH_FLAG_UMI = 0x0010, 194 | /* TODO complete */ 195 | }; 196 | 197 | struct awdl_data_path_state_tlv { 198 | uint8_t type; 199 | uint16_t length; 200 | uint16_t flags; 201 | char country_code[3]; 202 | uint16_t social_channels; 203 | struct ether_addr awdl_addr; 204 | uint16_t ext_flags; 205 | /* uint32_t logtrigger_id; if (ext_flags | 0x4) */ 206 | } __attribute__((__packed__)); 207 | 208 | struct awdl_arpa_tlv { 209 | uint8_t type; 210 | uint16_t length; 211 | uint8_t flags; /* 3 is only valid flag 212 | * found in IO80211Family.kext 213 | * method: IO80211ServiceRequestDescriptor::initWithArpaTLV(apple80211_awdl_arpa_tlv *,ether_addr *,userPrintCtx *) */ 214 | uint8_t name_length; 215 | char name[1]; 216 | /* uint16_t suffix */ 217 | } __attribute__((__packed__)); 218 | 219 | struct awdl_version_tlv { 220 | uint8_t type; 221 | uint16_t length; 222 | uint8_t version; 223 | uint8_t devclass; 224 | } __attribute__((__packed__)); 225 | 226 | const char *awdl_tlv_as_str(uint8_t type); 227 | 228 | #endif /* AWDL_FRAME_H_ */ 229 | -------------------------------------------------------------------------------- /src/hashmap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Generic map implementation. 3 | */ 4 | #include "hashmap.h" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "siphash24.h" 11 | 12 | #define INITIAL_SIZE (256) 13 | #define MAX_CHAIN_LENGTH (8) 14 | 15 | /* We need to keep keys and values */ 16 | typedef struct _hashmap_element{ 17 | mkey_t key; 18 | int in_use; 19 | any_t data; 20 | } hashmap_element; 21 | 22 | /* A hashmap has some maximum size and current size, 23 | * as well as the data to hold. */ 24 | typedef struct _hashmap_map{ 25 | int table_size; 26 | int size; 27 | int key_size; /* size of user's mkey_t in bytes */ 28 | hashmap_element *data; 29 | unsigned char seed[siphash24_KEYBYTES]; 30 | } hashmap_map; 31 | 32 | /* 33 | * Return an empty hashmap, or NULL on failure. 34 | */ 35 | map_t hashmap_new(int key_size) { 36 | hashmap_map* m = (hashmap_map*) malloc(sizeof(hashmap_map)); 37 | if(!m) goto err; 38 | 39 | m->data = (hashmap_element*) calloc(INITIAL_SIZE, sizeof(hashmap_element)); 40 | if(!m->data) goto err; 41 | 42 | m->table_size = INITIAL_SIZE; 43 | m->size = 0; 44 | m->key_size = key_size; 45 | 46 | /* TODO init seed randomly */ 47 | memset(m->seed, 0, siphash24_KEYBYTES); 48 | 49 | return m; 50 | err: 51 | if (m) 52 | hashmap_free(m); 53 | return NULL; 54 | } 55 | 56 | /* 57 | * Hashing function for a string 58 | */ 59 | unsigned int hashmap_hash_int(hashmap_map *m, mkey_t key) { 60 | uint64_t hash; 61 | siphash24((unsigned char *) &hash, key, m->key_size, m->seed); 62 | return hash % m->table_size; 63 | } 64 | 65 | /* 66 | * Return the integer of the location in data 67 | * to store the point to the item, or MAP_FULL. 68 | */ 69 | int hashmap_hash(map_t in, mkey_t key){ 70 | int curr; 71 | int i; 72 | 73 | /* Cast the hashmap */ 74 | hashmap_map* m = (hashmap_map *) in; 75 | 76 | /* If full, return immediately */ 77 | if(m->size >= (m->table_size/2)) return MAP_FULL; 78 | 79 | /* Find the best index */ 80 | curr = hashmap_hash_int(m, key); 81 | 82 | /* Linear probing */ 83 | for(i = 0; i< MAX_CHAIN_LENGTH; i++){ 84 | if(m->data[curr].in_use == 0) 85 | return curr; 86 | 87 | if (m->data[curr].in_use == 1 && (memcmp(m->data[curr].key, key, m->key_size) == 0)) 88 | return curr; 89 | 90 | curr = (curr + 1) % m->table_size; 91 | } 92 | 93 | return MAP_FULL; 94 | } 95 | 96 | /* 97 | * Doubles the size of the hashmap, and rehashes all the elements 98 | */ 99 | enum map_status hashmap_rehash(map_t in){ 100 | int i; 101 | int old_size; 102 | hashmap_element* curr; 103 | 104 | /* Setup the new elements */ 105 | hashmap_map *m = (hashmap_map *) in; 106 | hashmap_element* temp = (hashmap_element *) 107 | calloc(2 * m->table_size, sizeof(hashmap_element)); 108 | if(!temp) return MAP_OMEM; 109 | 110 | /* Update the array */ 111 | curr = m->data; 112 | m->data = temp; 113 | 114 | /* Update the size */ 115 | old_size = m->table_size; 116 | m->table_size = 2 * m->table_size; 117 | m->size = 0; 118 | 119 | /* Rehash the elements */ 120 | for(i = 0; i < old_size; i++){ 121 | int status; 122 | 123 | if (curr[i].in_use == 0) 124 | continue; 125 | 126 | status = hashmap_put(m, curr[i].key, curr[i].data); 127 | if (status != MAP_OK) 128 | return status; 129 | } 130 | 131 | free(curr); 132 | 133 | return MAP_OK; 134 | } 135 | 136 | /* 137 | * Add a pointer to the hashmap with some key 138 | */ 139 | enum map_status hashmap_put(map_t in, mkey_t key, any_t value){ 140 | int index; 141 | hashmap_map* m; 142 | 143 | /* Cast the hashmap */ 144 | m = (hashmap_map *) in; 145 | 146 | /* Find a place to put our value */ 147 | index = hashmap_hash(in, key); 148 | while(index == MAP_FULL){ 149 | if (hashmap_rehash(in) == MAP_OMEM) { 150 | return MAP_OMEM; 151 | } 152 | index = hashmap_hash(in, key); 153 | } 154 | 155 | /* Set the data */ 156 | m->data[index].data = value; 157 | m->data[index].key = key; 158 | m->data[index].in_use = 1; 159 | m->size++; 160 | 161 | return MAP_OK; 162 | } 163 | 164 | /* 165 | * Get your pointer out of the hashmap with a key 166 | */ 167 | enum map_status hashmap_get(map_t in, mkey_t key, any_t *arg, int remove) { 168 | int curr; 169 | int i; 170 | hashmap_map* m; 171 | 172 | /* Cast the hashmap */ 173 | m = (hashmap_map *) in; 174 | 175 | /* Find data location */ 176 | curr = hashmap_hash_int(m, key); 177 | 178 | /* Linear probing, if necessary */ 179 | for(i = 0; idata[curr].in_use; 182 | if (in_use == 1){ 183 | if (memcmp(m->data[curr].key, key, m->key_size) == 0) { 184 | if (arg) 185 | *arg = (m->data[curr].data); 186 | 187 | if (remove) { 188 | /* Blank out the fields */ 189 | m->data[curr].in_use = 0; 190 | m->data[curr].data = NULL; 191 | m->data[curr].key = NULL; 192 | 193 | /* Reduce the size */ 194 | m->size--; 195 | } 196 | 197 | return MAP_OK; 198 | } 199 | } 200 | 201 | curr = (curr + 1) % m->table_size; 202 | } 203 | 204 | if (arg) 205 | *arg = NULL; 206 | 207 | /* Not found */ 208 | return MAP_MISSING; 209 | } 210 | 211 | /* Deallocate the hashmap */ 212 | void hashmap_free(map_t in){ 213 | hashmap_map* m = (hashmap_map*) in; 214 | free(m->data); 215 | free(m); 216 | } 217 | 218 | /* Return the length of the hashmap */ 219 | int hashmap_length(map_t in){ 220 | hashmap_map* m = (hashmap_map *) in; 221 | if(m != NULL) return m->size; 222 | else return 0; 223 | } 224 | 225 | typedef struct _hashmap_it { 226 | hashmap_map *map; 227 | int i; /* current index */ 228 | } hashmap_it; 229 | 230 | /** 231 | * Get a new iterator. 232 | * @param in the hashmap 233 | * @return a new iterator of hashmap 234 | */ 235 | map_it_t hashmap_it_new(map_t in) { 236 | hashmap_it *it = (hashmap_it *) malloc(sizeof(hashmap_it)); 237 | it->map = (hashmap_map *) in; 238 | it->i = -1; 239 | return (map_it_t) it; 240 | } 241 | 242 | /** 243 | * Get next element in hashmap. You should not modify the the map while iterating. 244 | * @param it hashmap iterator 245 | * @param key set to current element's key if return MAP_OK 246 | * @param value set to current element's value if return MAP_OK 247 | * @return MAP_OK if had next, MAP_MISSING otherwise 248 | */ 249 | enum map_status hashmap_it_next(map_it_t _it, mkey_t *key, any_t *value) { 250 | hashmap_it *it = (hashmap_it *) _it; 251 | 252 | /* Linear probing */ 253 | for (it->i++; it->i < it->map->table_size; it->i++) 254 | if (it->map->data[it->i].in_use != 0) { 255 | if (key) 256 | *key = it->map->data[it->i].key; 257 | if (value) 258 | *value = (any_t) (it->map->data[it->i].data); 259 | return MAP_OK; 260 | } 261 | 262 | return MAP_MISSING; 263 | } 264 | 265 | /** 266 | * Removes current element from hashmap. 267 | * @param it hashmap iterator 268 | * @return MAP_OK if iterator points to valid element, MAP_MISSING otherwise 269 | */ 270 | enum map_status hashmap_it_remove(map_it_t _it) { 271 | hashmap_it *it = (hashmap_it *) _it; 272 | 273 | if (it->i < 0 || it->i >= it->map->table_size) 274 | return MAP_MISSING; 275 | 276 | if (!it->map->data[it->i].in_use) 277 | /* could be that we are calling remove on an already removed element */ 278 | return MAP_MISSING; 279 | 280 | it->map->data[it->i].in_use = 0; 281 | it->map->data[it->i].data = NULL; 282 | it->map->data[it->i].key = NULL; 283 | 284 | /* Reduce the size */ 285 | it->map->size--; 286 | 287 | return MAP_OK; 288 | } 289 | 290 | /** 291 | * Frees interator. {@code it} must not be used after calling this method. 292 | * @param it hashmap iterator 293 | */ 294 | void hashmap_it_free(map_it_t _it) { 295 | hashmap_it *it = (hashmap_it *) _it; 296 | free(it); 297 | } 298 | -------------------------------------------------------------------------------- /src/hashmap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Generic hashmap manipulation functions 3 | * 4 | * Originally by Elliot C Back - http://elliottback.com/wp/hashmap-implementation-in-c/ 5 | * 6 | * Modified by Pete Warden to fix a serious performance problem, support strings as keys 7 | * and removed thread synchronization - http://petewarden.typepad.com 8 | * 9 | * Modified by Milan Stute to support arbitrary key types. 10 | */ 11 | #ifndef __HASHMAP_H__ 12 | #define __HASHMAP_H__ 13 | 14 | #include 15 | 16 | enum map_status { 17 | MAP_OK = 0, /* OK */ 18 | MAP_OMEM = -1, /* Out of Memory */ 19 | MAP_FULL = -2, /* Hashmap is full */ 20 | MAP_MISSING = -3, /* No such element */ 21 | }; 22 | 23 | /* 24 | * any_t is a pointer. This allows you to put arbitrary structures in 25 | * the hashmap. 26 | */ 27 | typedef void *any_t; 28 | 29 | /* 30 | * Key can be anything. But user has to provide byte length of type. 31 | */ 32 | typedef any_t mkey_t; 33 | 34 | /* 35 | * map_t is a pointer to an internally maintained data structure. 36 | * Clients of this package do not need to know how hashmaps are 37 | * represented. They see and manipulate only map_t's. 38 | */ 39 | typedef any_t map_t; 40 | 41 | /* 42 | * Return an empty hashmap. Returns NULL if empty. 43 | */ 44 | extern map_t hashmap_new(int mkey_len); 45 | 46 | /* 47 | * Add an element to the hashmap. Return MAP_OK or MAP_OMEM. 48 | */ 49 | extern enum map_status hashmap_put(map_t in, mkey_t key, any_t value); 50 | 51 | /* 52 | * Get an element from the hashmap. Return MAP_OK or MAP_MISSING. 53 | * If remove is true, element will be removed if it exists. 54 | * arg will be set to the value if found, can be NULL if not required 55 | */ 56 | extern enum map_status hashmap_get(map_t in, mkey_t key, any_t *arg, int remove); 57 | 58 | /* 59 | * Free the hashmap 60 | */ 61 | extern void hashmap_free(map_t in); 62 | 63 | /* 64 | * Get the current size of a hashmap 65 | */ 66 | extern int hashmap_length(map_t in); 67 | 68 | /** 69 | * Opaque iterator type 70 | */ 71 | typedef any_t map_it_t; 72 | 73 | /** 74 | * Get a new iterator. 75 | * @param in the hashmap 76 | * @return a new iterator of hashmap 77 | */ 78 | extern map_it_t hashmap_it_new(map_t in); 79 | 80 | /** 81 | * Get next element in hashmap. You should not modify the the map while iterating. 82 | * @param it hashmap iterator 83 | * @param key set to current element's key if return MAP_OK 84 | * @param value set to current element's value if return MAP_OK 85 | * @return MAP_OK if had next, MAP_MISSING otherwise 86 | */ 87 | extern enum map_status hashmap_it_next(map_it_t it, mkey_t *key, any_t *value); 88 | 89 | /** 90 | * Removes current element from hashmap. 91 | * @param it hashmap iterator 92 | * @return MAP_OK if iterator points to valid element, MAP_MISSING otherwise 93 | */ 94 | extern enum map_status hashmap_it_remove(map_it_t it); 95 | 96 | /** 97 | * Frees interator. {@code it} must not be used after calling this method. 98 | * @param it hashmap iterator 99 | */ 100 | extern void hashmap_it_free(map_it_t it); 101 | 102 | #endif /* __HASHMAP_H__ */ 103 | -------------------------------------------------------------------------------- /src/ieee80211.h: -------------------------------------------------------------------------------- 1 | #ifndef IEEE80211_H_ 2 | #define IEEE80211_H_ 3 | 4 | #include 5 | 6 | #ifdef __APPLE__ 7 | 8 | #include 9 | 10 | #else 11 | #include 12 | #endif 13 | 14 | /* Some relevant Ethernet Protocol IDs */ 15 | #define ETH_P_IP 0x0800 /* Internet Protocol packet */ 16 | #define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */ 17 | 18 | #define OUI_LEN 3 19 | 20 | struct oui { 21 | uint8_t byte[OUI_LEN]; 22 | } __attribute__((__packed__)); 23 | 24 | #define FCS_LEN 4 25 | 26 | #define IEEE80211_FCTL_VERS 0x0003 27 | #define IEEE80211_FCTL_FTYPE 0x000c 28 | #define IEEE80211_FCTL_STYPE 0x00f0 29 | #define IEEE80211_FCTL_TODS 0x0100 30 | #define IEEE80211_FCTL_FROMDS 0x0200 31 | #define IEEE80211_FCTL_MOREFRAGS 0x0400 32 | #define IEEE80211_FCTL_RETRY 0x0800 33 | #define IEEE80211_FCTL_PM 0x1000 34 | #define IEEE80211_FCTL_MOREDATA 0x2000 35 | #define IEEE80211_FCTL_PROTECTED 0x4000 36 | #define IEEE80211_FCTL_ORDER 0x8000 37 | #define IEEE80211_FCTL_CTL_EXT 0x0f00 38 | 39 | #define IEEE80211_SCTL_FRAG 0x000F 40 | #define IEEE80211_SCTL_SEQ 0xFFF0 41 | 42 | #define IEEE80211_FTYPE_MGMT 0x0000 43 | #define IEEE80211_FTYPE_CTL 0x0004 44 | #define IEEE80211_FTYPE_DATA 0x0008 45 | #define IEEE80211_FTYPE_EXT 0x000c 46 | 47 | /* management */ 48 | #define IEEE80211_STYPE_ASSOC_REQ 0x0000 49 | #define IEEE80211_STYPE_ASSOC_RESP 0x0010 50 | #define IEEE80211_STYPE_REASSOC_REQ 0x0020 51 | #define IEEE80211_STYPE_REASSOC_RESP 0x0030 52 | #define IEEE80211_STYPE_PROBE_REQ 0x0040 53 | #define IEEE80211_STYPE_PROBE_RESP 0x0050 54 | #define IEEE80211_STYPE_BEACON 0x0080 55 | #define IEEE80211_STYPE_ATIM 0x0090 56 | #define IEEE80211_STYPE_DISASSOC 0x00A0 57 | #define IEEE80211_STYPE_AUTH 0x00B0 58 | #define IEEE80211_STYPE_DEAUTH 0x00C0 59 | #define IEEE80211_STYPE_ACTION 0x00D0 60 | 61 | /* control */ 62 | #define IEEE80211_STYPE_CTL_EXT 0x0060 63 | #define IEEE80211_STYPE_BACK_REQ 0x0080 64 | #define IEEE80211_STYPE_BACK 0x0090 65 | #define IEEE80211_STYPE_PSPOLL 0x00A0 66 | #define IEEE80211_STYPE_RTS 0x00B0 67 | #define IEEE80211_STYPE_CTS 0x00C0 68 | #define IEEE80211_STYPE_ACK 0x00D0 69 | #define IEEE80211_STYPE_CFEND 0x00E0 70 | #define IEEE80211_STYPE_CFENDACK 0x00F0 71 | 72 | /* data */ 73 | #define IEEE80211_STYPE_DATA 0x0000 74 | #define IEEE80211_STYPE_DATA_CFACK 0x0010 75 | #define IEEE80211_STYPE_DATA_CFPOLL 0x0020 76 | #define IEEE80211_STYPE_DATA_CFACKPOLL 0x0030 77 | #define IEEE80211_STYPE_NULLFUNC 0x0040 78 | #define IEEE80211_STYPE_CFACK 0x0050 79 | #define IEEE80211_STYPE_CFPOLL 0x0060 80 | #define IEEE80211_STYPE_CFACKPOLL 0x0070 81 | #define IEEE80211_STYPE_QOS_DATA 0x0080 82 | #define IEEE80211_STYPE_QOS_DATA_CFACK 0x0090 83 | #define IEEE80211_STYPE_QOS_DATA_CFPOLL 0x00A0 84 | #define IEEE80211_STYPE_QOS_DATA_CFACKPOLL 0x00B0 85 | #define IEEE80211_STYPE_QOS_NULLFUNC 0x00C0 86 | #define IEEE80211_STYPE_QOS_CFACK 0x00D0 87 | #define IEEE80211_STYPE_QOS_CFPOLL 0x00E0 88 | #define IEEE80211_STYPE_QOS_CFACKPOLL 0x00F0 89 | 90 | /* extension, added by 802.11ad */ 91 | #define IEEE80211_STYPE_DMG_BEACON 0x0000 92 | 93 | /* control extension - for IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTL_EXT */ 94 | #define IEEE80211_CTL_EXT_POLL 0x2000 95 | #define IEEE80211_CTL_EXT_SPR 0x3000 96 | #define IEEE80211_CTL_EXT_GRANT 0x4000 97 | #define IEEE80211_CTL_EXT_DMG_CTS 0x5000 98 | #define IEEE80211_CTL_EXT_DMG_DTS 0x6000 99 | #define IEEE80211_CTL_EXT_SSW 0x8000 100 | #define IEEE80211_CTL_EXT_SSW_FBACK 0x9000 101 | #define IEEE80211_CTL_EXT_SSW_ACK 0xa000 102 | 103 | /* Maximum size for the MA-UNITDATA primitive, 802.11 standard section 104 | 6.2.1.1.2. 105 | 802.11e clarifies the figure in section 7.1.2. The frame body is 106 | up to 2304 octets long (maximum MSDU size) plus any crypt overhead. */ 107 | #define IEEE80211_MAX_DATA_LEN 2304 108 | /* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */ 109 | #define IEEE80211_MAX_FRAME_LEN 2352 110 | 111 | #define IEEE80211_QOS_CTL_LEN 2 112 | /* 1d tag mask */ 113 | #define IEEE80211_QOS_CTL_TAG1D_MASK 0x0007 114 | /* TID mask */ 115 | #define IEEE80211_QOS_CTL_TID_MASK 0x000f 116 | /* EOSP */ 117 | #define IEEE80211_QOS_CTL_EOSP 0x0010 118 | /* ACK policy */ 119 | #define IEEE80211_QOS_CTL_ACK_POLICY_NORMAL 0x0000 120 | #define IEEE80211_QOS_CTL_ACK_POLICY_NOACK 0x0020 121 | #define IEEE80211_QOS_CTL_ACK_POLICY_NO_EXPL 0x0040 122 | #define IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK 0x0060 123 | #define IEEE80211_QOS_CTL_ACK_POLICY_MASK 0x0060 124 | /* A-MSDU 802.11n */ 125 | #define IEEE80211_QOS_CTL_A_MSDU_PRESENT 0x0080 126 | /* Mesh Control 802.11s */ 127 | #define IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT 0x0100 128 | 129 | /* Mesh Power Save Level */ 130 | #define IEEE80211_QOS_CTL_MESH_PS_LEVEL 0x0200 131 | /* Mesh Receiver Service Period Initiated */ 132 | #define IEEE80211_QOS_CTL_RSPI 0x0400 133 | 134 | /* 135 | * 802.11n Management Action Frames 136 | * 137 | * Adapted from 'ieee80211_hdr_3addr' in 138 | */ 139 | struct ieee80211_hdr { 140 | uint16_t frame_control; 141 | uint16_t duration_id; 142 | struct ether_addr addr1; /* dst */ 143 | struct ether_addr addr2; /* src */ 144 | struct ether_addr addr3; /* bssid */ 145 | uint16_t seq_ctrl; 146 | } __attribute__((__packed__)); 147 | 148 | struct llc_hdr { 149 | uint8_t dsap; 150 | uint8_t ssap; 151 | uint8_t control; 152 | /* SNAP extension */ 153 | struct oui oui; 154 | uint16_t pid; 155 | } __attribute__((__packed__)); 156 | 157 | /** 158 | * ieee80211_tu_to_usec - convert time units (TU) to microseconds 159 | * @tu: the TUs 160 | */ 161 | static inline unsigned long ieee80211_tu_to_usec(unsigned long tu) { 162 | return 1024 * tu; 163 | } 164 | 165 | static inline unsigned long ieee80211_usec_to_tu(unsigned long usec) { 166 | return usec / 1024; 167 | } 168 | 169 | int ieee80211_channel_to_frequency(int chan); 170 | int ieee80211_frequency_to_channel(int freq); 171 | 172 | static inline int ieee80211_radiotap_type_to_mask(int type) { 173 | return 1 << type; 174 | } 175 | 176 | static inline int ieee80211_radiotap_rate_to_val(int rate) { 177 | return 2 * rate; 178 | } 179 | 180 | #endif /* IEEE80211_H_ */ 181 | -------------------------------------------------------------------------------- /src/log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2017 rxi 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 | * IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "log.h" 30 | 31 | static struct { 32 | void *udata; 33 | log_LockFn lock; 34 | FILE *fp; 35 | int level; 36 | int quiet; 37 | } L; 38 | 39 | 40 | static const char *level_names[] = { 41 | "EMERG", "ALERT", "CRIT", "ERROR", "WARN", "NOTICE", "INFO", "DEBUG", "TRACE" 42 | }; 43 | 44 | 45 | #ifdef LOG_USE_COLOR 46 | static const char *level_colors[] = { 47 | "\x1b[94m", "\x1b[36m", "\x1b[32m", "\x1b[33m", "\x1b[31m", "\x1b[35m" 48 | }; 49 | #endif 50 | 51 | 52 | static void lock(void) { 53 | if (L.lock) { 54 | L.lock(L.udata, 1); 55 | } 56 | } 57 | 58 | 59 | static void unlock(void) { 60 | if (L.lock) { 61 | L.lock(L.udata, 0); 62 | } 63 | } 64 | 65 | 66 | void log_set_udata(void *udata) { 67 | L.udata = udata; 68 | } 69 | 70 | 71 | void log_set_lock(log_LockFn fn) { 72 | L.lock = fn; 73 | } 74 | 75 | 76 | void log_set_fp(FILE *fp) { 77 | L.fp = fp; 78 | } 79 | 80 | 81 | void log_set_level(int level) { 82 | L.level = level; 83 | } 84 | 85 | 86 | void log_set_quiet(int enable) { 87 | L.quiet = enable ? 1 : 0; 88 | } 89 | 90 | 91 | int log_log(int level, const char *file, int line, const char *fmt, ...) { 92 | if (level > L.level) { 93 | return 0; 94 | } 95 | 96 | /* Acquire lock */ 97 | lock(); 98 | 99 | /* Get current time */ 100 | time_t t = time(NULL); 101 | struct tm lt; 102 | localtime_r(&t, <); 103 | 104 | /* Log to stderr */ 105 | if (!L.quiet) { 106 | va_list args; 107 | char buf[16]; 108 | buf[strftime(buf, sizeof(buf), "%H:%M:%S", <)] = '\0'; 109 | #ifdef LOG_USE_COLOR 110 | fprintf( 111 | stderr, "%s %s%-5s\x1b[0m \x1b[90m%s:%d:\x1b[0m ", 112 | buf, level_colors[level], level_names[level], file, line); 113 | #else 114 | fprintf(stderr, "%s %-5s: ", buf, level_names[level]); 115 | #endif 116 | va_start(args, fmt); 117 | vfprintf(stderr, fmt, args); 118 | va_end(args); 119 | fprintf(stderr, "\n"); 120 | } 121 | 122 | /* Log to file */ 123 | if (L.fp) { 124 | va_list args; 125 | char buf[32]; 126 | buf[strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", <)] = '\0'; 127 | fprintf(L.fp, "%s %-6s %s:%d: ", buf, level_names[level], file, line); 128 | va_start(args, fmt); 129 | vfprintf(L.fp, fmt, args); 130 | va_end(args); 131 | fprintf(L.fp, "\n"); 132 | } 133 | 134 | /* Release lock */ 135 | unlock(); 136 | 137 | return 1; 138 | } 139 | -------------------------------------------------------------------------------- /src/log.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 rxi 3 | * 4 | * This library is free software; you can redistribute it and/or modify it 5 | * under the terms of the MIT license. See `log.c` for details. 6 | */ 7 | 8 | #ifndef LOG_H 9 | #define LOG_H 10 | 11 | #include 12 | #include 13 | 14 | #define LOG_VERSION "0.1.0" 15 | 16 | typedef void (*log_LockFn)(void *udata, int lock); 17 | 18 | #ifndef LOG_CRIT 19 | #define LOG_EMERG 0 /* system is unusable */ 20 | #define LOG_ALERT 1 /* action must be taken immediately */ 21 | #define LOG_CRIT 2 /* critical conditions */ 22 | #define LOG_ERR 3 /* error conditions */ 23 | #define LOG_WARNING 4 /* warning conditions */ 24 | #define LOG_NOTICE 5 /* normal but significant condition */ 25 | #define LOG_INFO 6 /* informational */ 26 | #define LOG_DEBUG 7 /* debug-level messages */ 27 | #endif 28 | #define LOG_TRACE 8 /* trace-level messages */ 29 | 30 | #define log_crit(...) log_log(LOG_CRIT, __FILE__, __LINE__, __VA_ARGS__) 31 | #define log_error(...) log_log(LOG_ERR, __FILE__, __LINE__, __VA_ARGS__) 32 | #define log_warn(...) log_log(LOG_WARNING, __FILE__, __LINE__, __VA_ARGS__) 33 | #define log_notice(...) log_log(LOG_NOTICE, __FILE__, __LINE__, __VA_ARGS__) 34 | #define log_info(...) log_log(LOG_INFO, __FILE__, __LINE__, __VA_ARGS__) 35 | #define log_debug(...) log_log(LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__) 36 | #define log_trace(...) log_log(LOG_TRACE, __FILE__, __LINE__, __VA_ARGS__) 37 | 38 | void log_set_udata(void *udata); 39 | 40 | void log_set_lock(log_LockFn fn); 41 | 42 | void log_set_fp(FILE *fp); 43 | 44 | void log_set_level(int level); 45 | 46 | void log_set_quiet(int enable); 47 | 48 | int log_log(int level, const char *file, int line, const char *fmt, ...); 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/peers.c: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include "peers.h" 25 | #include "hashmap.h" 26 | #include "log.h" 27 | 28 | #define PEERS_DEFAULT_TIMEOUT 2000000 /* in ms */ 29 | #define PEERS_DEFAULT_CLEAN_INTERVAL 1000000 /* in ms */ 30 | 31 | void awdl_peer_state_init(struct awdl_peer_state *state) { 32 | state->peers = awdl_peers_init(); 33 | state->timeout = PEERS_DEFAULT_TIMEOUT; 34 | state->clean_interval = PEERS_DEFAULT_CLEAN_INTERVAL; 35 | } 36 | 37 | awdl_peers_t awdl_peers_init() { 38 | return (awdl_peers_t) hashmap_new(sizeof(struct ether_addr)); 39 | } 40 | 41 | void awdl_peers_free(awdl_peers_t peers) { 42 | struct awdl_peer *peer; 43 | map_t map = (map_t) peers; 44 | 45 | /* Remove all allocated peers */ 46 | map_it_t it = hashmap_it_new(map); 47 | while (hashmap_it_next(it, NULL, (any_t *) &peer) == MAP_OK) { 48 | hashmap_it_remove(it); 49 | free(peer); 50 | } 51 | hashmap_it_free(it); 52 | 53 | /* Remove hashmap itself */ 54 | hashmap_free(peers); 55 | } 56 | 57 | int awdl_peers_length(awdl_peers_t peers) { 58 | map_t map = (map_t) peers; 59 | return hashmap_length(map); 60 | } 61 | 62 | static int awdl_peer_is_valid(const struct awdl_peer *peer) { 63 | return peer->sent_mif && peer->devclass && peer->version; 64 | } 65 | 66 | struct awdl_peer *awdl_peer_new(const struct ether_addr *addr) { 67 | struct awdl_peer *peer = (struct awdl_peer *) malloc(sizeof(struct awdl_peer)); 68 | *(struct ether_addr *) &peer->addr = *addr; 69 | peer->last_update = 0; 70 | awdl_election_state_init(&peer->election, addr); 71 | awdl_chanseq_init_static(peer->sequence, &CHAN_NULL); 72 | peer->sync_offset = 0; 73 | peer->devclass = 0; 74 | peer->version = 0; 75 | peer->supports_v2 = 0; 76 | peer->sent_mif = 0; 77 | strcpy(peer->name, ""); 78 | strcpy(peer->country_code, "NA"); 79 | peer->is_valid = 0; 80 | return peer; 81 | } 82 | 83 | enum peers_status 84 | awdl_peer_add(awdl_peers_t peers, const struct ether_addr *_addr, uint64_t now, awdl_peer_cb cb, void *arg) { 85 | int status, result; 86 | map_t map = (map_t) peers; 87 | mkey_t addr = (mkey_t) _addr; 88 | struct awdl_peer *peer; 89 | status = hashmap_get(map, addr, (any_t *) &peer, 0 /* do not remove */); 90 | if (status == MAP_MISSING) 91 | peer = awdl_peer_new(_addr); /* create new entry */ 92 | 93 | /* update */ 94 | peer->last_update = now; 95 | 96 | if (status == MAP_OK) { 97 | result = PEERS_UPDATE; 98 | goto out; 99 | } 100 | 101 | status = hashmap_put(map, (mkey_t) &peer->addr, peer); 102 | if (status != MAP_OK) { 103 | free(peer); 104 | return PEERS_INTERNAL; 105 | } 106 | result = PEERS_OK; 107 | out: 108 | if (!peer->is_valid && awdl_peer_is_valid(peer)) { 109 | /* peer has turned valid */ 110 | peer->is_valid = 1; 111 | log_info("add peer %s (%s)", ether_ntoa(&peer->addr), peer->name); 112 | if (cb) 113 | cb(peer, arg); 114 | } 115 | return result; 116 | } 117 | 118 | enum peers_status awdl_peer_remove(awdl_peers_t peers, const struct ether_addr *_addr, awdl_peer_cb cb, void *arg) { 119 | int status; 120 | map_t map = (map_t) peers; 121 | mkey_t addr = (mkey_t) _addr; 122 | struct awdl_peer *peer; 123 | status = hashmap_get(map, addr, (any_t *) &peer, 1 /* remove */); 124 | if (status == MAP_MISSING) 125 | return PEERS_MISSING; 126 | if (peer->is_valid) { 127 | log_info("remove peer %s (%s)", ether_ntoa(&peer->addr), peer->name); 128 | if (cb) 129 | cb(peer, arg); 130 | } 131 | free(peer); 132 | return PEERS_OK; 133 | } 134 | 135 | enum peers_status awdl_peer_get(awdl_peers_t peers, const struct ether_addr *_addr, struct awdl_peer **peer) { 136 | int status; 137 | map_t map = (map_t) peers; 138 | mkey_t addr = (mkey_t) _addr; 139 | status = hashmap_get(map, addr, (any_t *) peer, 0 /* keep */); 140 | if (status == MAP_MISSING) 141 | return PEERS_MISSING; 142 | return PEERS_OK; 143 | } 144 | 145 | int awdl_peer_print(const struct awdl_peer *peer, char *str, int len) { 146 | char *cur = str, *const end = str + len; 147 | if (strlen(peer->name)) 148 | cur += snprintf(cur, cur < end ? end - cur : 0, "%s: ", peer->name); 149 | else 150 | cur += snprintf(cur, cur < end ? end - cur : 0, ": "); 151 | cur += awdl_election_tree_print(&peer->election, cur, end - cur); 152 | return cur - str; 153 | } 154 | 155 | int awdl_peers_print(awdl_peers_t peers, char *str, int len) { 156 | char *cur = str, *const end = str + len; 157 | map_t map = (map_t) peers; 158 | map_it_t it = hashmap_it_new(map); 159 | struct awdl_peer *peer; 160 | 161 | while (hashmap_it_next(it, NULL, (any_t *) &peer) == MAP_OK) { 162 | cur += awdl_peer_print(peer, cur, end - cur); 163 | cur += snprintf(cur, cur < end ? end - cur : 0, "\n"); 164 | } 165 | 166 | hashmap_it_free(it); 167 | return cur - str; 168 | } 169 | 170 | void awdl_peers_remove(awdl_peers_t peers, uint64_t before, awdl_peer_cb cb, void *arg) { 171 | map_t map = (map_t) peers; 172 | map_it_t it = hashmap_it_new(map); 173 | struct awdl_peer *peer; 174 | 175 | while (hashmap_it_next(it, NULL, (any_t *) &peer) == MAP_OK) { 176 | if (peer->last_update < before) { 177 | if (peer->is_valid) { 178 | log_info("remove peer %s (%s)", ether_ntoa(&peer->addr), peer->name); 179 | if (cb) 180 | cb(peer, arg); 181 | } 182 | hashmap_it_remove(it); 183 | free(peer); 184 | } 185 | } 186 | hashmap_it_free(it); 187 | } 188 | 189 | awdl_peers_it_t awdl_peers_it_new(awdl_peers_t in) { 190 | return (awdl_peers_it_t) hashmap_it_new((map_t) in); 191 | } 192 | 193 | enum peers_status awdl_peers_it_next(awdl_peers_it_t it, struct awdl_peer **peer) { 194 | int s = hashmap_it_next((map_it_t) it, 0, (any_t *) peer); 195 | if (s == MAP_OK) 196 | return PEERS_OK; 197 | else 198 | return PEERS_MISSING; 199 | } 200 | 201 | enum peers_status awdl_peers_it_remove(awdl_peers_it_t it) { 202 | int s = hashmap_it_remove((map_it_t) it); 203 | if (s == MAP_OK) 204 | return PEERS_OK; 205 | else 206 | return PEERS_MISSING; 207 | } 208 | 209 | void awdl_peers_it_free(awdl_peers_it_t it) { 210 | hashmap_it_free((map_it_t) it); 211 | } 212 | -------------------------------------------------------------------------------- /src/peers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #ifndef AWDL_PEERS_H 21 | #define AWDL_PEERS_H 22 | 23 | #include 24 | #include 25 | 26 | #include "election.h" 27 | #include "channel.h" 28 | 29 | #define HOST_NAME_LENGTH_MAX 64 30 | 31 | enum peers_status { 32 | PEERS_UPDATE = 1, /* Peer updated */ 33 | PEERS_OK = 0, /* New peer added */ 34 | PEERS_MISSING = -1, /* Peer does not exist */ 35 | PEERS_INTERNAL = -2, /* Internal error */ 36 | }; 37 | 38 | struct awdl_peer { 39 | const struct ether_addr addr; 40 | uint64_t last_update; 41 | struct awdl_election_state election; 42 | struct awdl_chan sequence[AWDL_CHANSEQ_LENGTH]; 43 | uint64_t sync_offset; 44 | char name[HOST_NAME_LENGTH_MAX + 1]; /* space for trailing zero */ 45 | char country_code[2 + 1]; 46 | struct ether_addr infra_addr; 47 | uint8_t version; 48 | uint8_t devclass; 49 | uint8_t supports_v2 : 1; 50 | uint8_t sent_mif : 1; 51 | uint8_t is_valid : 1; 52 | }; 53 | 54 | typedef void (*awdl_peer_cb)(struct awdl_peer *, void *arg); 55 | 56 | typedef void *awdl_peers_t; 57 | 58 | struct awdl_peer_state { 59 | awdl_peers_t peers; 60 | uint64_t timeout; 61 | uint64_t clean_interval; 62 | }; 63 | 64 | void awdl_peer_state_init(struct awdl_peer_state *state); 65 | 66 | awdl_peers_t awdl_peers_init(); 67 | 68 | void awdl_peers_free(awdl_peers_t peers); 69 | 70 | int awdl_peers_length(awdl_peers_t peers); 71 | 72 | enum peers_status 73 | awdl_peer_add(awdl_peers_t peers, const struct ether_addr *addr, uint64_t now, awdl_peer_cb cb, void *arg); 74 | 75 | enum peers_status awdl_peer_remove(awdl_peers_t peers, const struct ether_addr *addr, awdl_peer_cb cb, void *arg); 76 | 77 | enum peers_status awdl_peer_get(awdl_peers_t peers, const struct ether_addr *addr, struct awdl_peer **peer); 78 | 79 | int awdl_peer_print(const struct awdl_peer *peer, char *str, int len); 80 | 81 | /** 82 | * Apply callback to and then remove all peers matching a filter 83 | * @param peers the awdl_peers_t instance 84 | * @param before remove all entries with an last_update timestamp {@code before} 85 | * @param cb the callback function, can be NULL 86 | * @param arg will be passed to callback function 87 | */ 88 | void awdl_peers_remove(awdl_peers_t peers, uint64_t before, awdl_peer_cb cb, void *arg); 89 | 90 | int awdl_peers_print(awdl_peers_t peers, char *str, int len); 91 | 92 | /* Iterator functions */ 93 | typedef void *awdl_peers_it_t; 94 | 95 | awdl_peers_it_t awdl_peers_it_new(awdl_peers_t in); 96 | 97 | enum peers_status awdl_peers_it_next(awdl_peers_it_t it, struct awdl_peer **peer); 98 | 99 | enum peers_status awdl_peers_it_remove(awdl_peers_it_t it); 100 | 101 | void awdl_peers_it_free(awdl_peers_it_t it); 102 | 103 | #endif /* ADWL_PEERS_H */ 104 | -------------------------------------------------------------------------------- /src/rx.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #ifndef AWDL_RX_H_ 21 | #define AWDL_RX_H_ 22 | 23 | #include "frame.h" 24 | #include "version.h" 25 | #include "state.h" 26 | 27 | enum RX_RESULT { 28 | RX_IGNORE_PEER = 6, 29 | RX_IGNORE_RSSI = 5, 30 | RX_IGNORE_FAILED_CRC = 4, 31 | RX_IGNORE_NOPROMISC = 3, 32 | RX_IGNORE_FROM_SELF = 2, 33 | RX_IGNORE = 1, 34 | RX_OK = 0, 35 | RX_UNEXPECTED_FORMAT = -1, 36 | RX_UNEXPECTED_TYPE = -2, 37 | RX_UNEXPECTED_VALUE = -3, 38 | RX_TOO_SHORT = -3, 39 | }; 40 | 41 | int awdl_handle_sync_params_tlv(struct awdl_peer *src, const struct buf *val, struct awdl_state *state, uint64_t tsft); 42 | 43 | int awdl_handle_chanseq_tlv(struct awdl_peer *src, const struct buf *val, struct awdl_state *state); 44 | 45 | int awdl_handle_election_params_tlv(struct awdl_peer *src, const struct buf *val, struct awdl_state *state); 46 | 47 | int awdl_handle_election_params_v2_tlv(struct awdl_peer *src, const struct buf *val, 48 | struct awdl_state *state); 49 | 50 | int awdl_handle_arpa_tlv(struct awdl_peer *src, const struct buf *val, struct awdl_state *state); 51 | 52 | int awdl_handle_data_path_state_tlv(struct awdl_peer *src, const struct buf *val, struct awdl_state *state); 53 | 54 | int awdl_handle_version_tlv(struct awdl_peer *src, const struct buf *val, struct awdl_state *state); 55 | 56 | int awdl_handle_tlv(struct awdl_peer *src, uint8_t type, const struct buf *val, 57 | struct awdl_state *state, uint64_t tsft); 58 | 59 | int awdl_parse_action_hdr(const struct buf *frame); 60 | 61 | int awdl_rx_action(const struct buf *frame, signed char rssi, uint64_t tsft, 62 | const struct ether_addr *src, const struct ether_addr *dst, struct awdl_state *state); 63 | 64 | int llc_parse(const struct buf *frame, struct llc_hdr *llc); 65 | int awdl_valid_llc_header(const struct buf *frame); 66 | 67 | int awdl_rx_data(const struct buf *frame, struct buf ***out, 68 | const struct ether_addr *src, const struct ether_addr *dst, struct awdl_state *state); 69 | 70 | int awdl_rx_data_amsdu(const struct buf *frame, struct buf ***out, 71 | const struct ether_addr *src, const struct ether_addr *dst, struct awdl_state *state); 72 | 73 | /** @brief Receive and process AWDL action and data frame 74 | * 75 | * @param frame input frame 76 | * @param data if {@code frame} points to a valid AWDL data frame, will point to converted Ethernet frame after function returns 77 | * @param state 78 | * @return RX_OK 79 | */ 80 | int awdl_rx(const struct buf *frame, struct buf ***data_frames, struct awdl_state *state); 81 | 82 | #endif /* AWDL_RX_H_ */ 83 | -------------------------------------------------------------------------------- /src/schedule.c: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #include "schedule.h" 21 | 22 | double usec_to_sec(uint64_t usec) { 23 | return usec / 1000000.; 24 | } 25 | 26 | uint64_t sec_to_usec(double sec) { 27 | return sec * 1000000; 28 | } 29 | 30 | bool awdl_same_channel_as_peer(const struct awdl_state *state, uint64_t now, const struct awdl_peer *peer) { 31 | int own_slot, peer_slot; 32 | int own_chan, peer_chan; 33 | 34 | own_slot = awdl_sync_current_eaw(now, &state->sync) % AWDL_CHANSEQ_LENGTH; 35 | peer_slot = awdl_sync_current_eaw(now + peer->sync_offset, &state->sync) % AWDL_CHANSEQ_LENGTH; 36 | 37 | own_chan = awdl_chan_num(state->channel.sequence[own_slot], state->channel.enc); 38 | peer_chan = awdl_chan_num(peer->sequence[peer_slot], state->channel.enc); 39 | 40 | return own_chan && (own_chan == peer_chan); 41 | } 42 | 43 | int awdl_is_multicast_eaw(const struct awdl_state *state, uint64_t now) { 44 | uint16_t slot = awdl_sync_current_eaw(now, &state->sync) % AWDL_CHANSEQ_LENGTH; 45 | return slot == 0 || slot == 10; 46 | } 47 | 48 | double awdl_can_send_in(const struct awdl_state *state, uint64_t now, int guard) { 49 | uint64_t next_aw = awdl_sync_next_aw_us(now, &state->sync); 50 | uint64_t _guard = ieee80211_tu_to_usec(guard); 51 | uint64_t eaw = ieee80211_tu_to_usec(64); 52 | 53 | return (next_aw < _guard) ? -usec_to_sec(_guard - next_aw) : ((eaw - next_aw < _guard) ? usec_to_sec( 54 | (_guard - (eaw - next_aw))) : 0); 55 | } 56 | 57 | double awdl_can_send_unicast_in(const struct awdl_state *state, const struct awdl_peer *peer, uint64_t now, int guard) { 58 | uint64_t next_aw = awdl_sync_next_aw_us(now, &state->sync); 59 | uint64_t _guard = ieee80211_tu_to_usec(guard); 60 | uint64_t eaw = ieee80211_tu_to_usec(64); 61 | 62 | if (!awdl_same_channel_as_peer(state, now, peer)) 63 | return usec_to_sec(next_aw); /* try again in the next slot */ 64 | 65 | if (next_aw < _guard) { /* we are at the end of slot */ 66 | if (awdl_same_channel_as_peer(state, now + eaw, peer)) { 67 | return 0; /* we are on the same channel in next slot, ignore guard */ 68 | } else { 69 | return -usec_to_sec(_guard - next_aw); 70 | } 71 | } else if (eaw - next_aw < _guard) { 72 | if (awdl_same_channel_as_peer(state, now - eaw, peer)) { 73 | return 0; /* we were on the same channel last slot, ignore guard */ 74 | } else { 75 | return usec_to_sec(_guard - (eaw - next_aw)); 76 | } 77 | } else { 78 | return 0; /* we are inside guard interval */ 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/schedule.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #ifndef AWDL_SCHEDULE_H_ 21 | #define AWDL_SCHEDULE_H_ 22 | 23 | #include 24 | 25 | #include "state.h" 26 | #include "peers.h" 27 | 28 | #define AWDL_UNICAST_GUARD_TU 3 29 | #define AWDL_MULTICAST_GUARD_TU 16 30 | 31 | double usec_to_sec(uint64_t usec); 32 | 33 | uint64_t sec_to_usec(double sec); 34 | 35 | /** 36 | * @brief Determine whether we are on the same non-zero channel as {@code peer}. 37 | * @param state our state 38 | * @param peer the other peer 39 | * @return true if we and {@code peer} are on the same non-zero channel, false otherwise 40 | */ 41 | bool awdl_same_channel_as_peer(const struct awdl_state *state, uint64_t now, const struct awdl_peer *peer); 42 | 43 | /** 44 | * @brief Determine whether we are 45 | * @param state 46 | * @return 47 | */ 48 | int awdl_is_multicast_eaw(const struct awdl_state *state, uint64_t now); 49 | 50 | /** 51 | * @brief Determine whether we are outside a certain guard interval. 52 | * 53 | * time 54 | * -----------------------> 55 | * +---+--------------+---+ 56 | * | G | ok to send | G | 57 | * +---+--------------+---+ 58 | * ^ ^ ^ 59 | * | | | 60 | * pos 0 neg 61 | * 62 | * return when (^) is now 63 | * 64 | * @param state AWDL state 65 | * @param guard guard interval in TU 66 | * @return 0 if we are outside guard interval, or a positive or negative time in seconds 67 | */ 68 | double awdl_can_send_in(const struct awdl_state *state, uint64_t now, int guard); 69 | 70 | double awdl_can_send_unicast_in(const struct awdl_state *state, const struct awdl_peer *peer, uint64_t now, int guard); 71 | 72 | #endif /* AWDL_SCHEDULE_H_ */ 73 | -------------------------------------------------------------------------------- /src/siphash24.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Extracted (and adjusted) from the Sodium library v1.0.16 3 | * https://libsodium.org 4 | */ 5 | #include 6 | #include 7 | 8 | #include "siphash24.h" 9 | 10 | #define LOAD64_LE(SRC) load64_le(SRC) 11 | static inline uint64_t 12 | load64_le(const uint8_t src[8]) 13 | { 14 | uint64_t w; 15 | memcpy(&w, src, sizeof w); 16 | return w; 17 | } 18 | 19 | #define STORE64_LE(DST, W) store64_le((DST), (W)) 20 | static inline void 21 | store64_le(uint8_t dst[8], uint64_t w) 22 | { 23 | memcpy(dst, &w, sizeof w); 24 | } 25 | 26 | #define ROTL64(X, B) rotl64((X), (B)) 27 | static inline uint64_t 28 | rotl64(const uint64_t x, const int b) 29 | { 30 | return (x << b) | (x >> (64 - b)); 31 | } 32 | 33 | #define SIPROUND \ 34 | do { \ 35 | v0 += v1; \ 36 | v1 = ROTL64(v1, 13); \ 37 | v1 ^= v0; \ 38 | v0 = ROTL64(v0, 32); \ 39 | v2 += v3; \ 40 | v3 = ROTL64(v3, 16); \ 41 | v3 ^= v2; \ 42 | v0 += v3; \ 43 | v3 = ROTL64(v3, 21); \ 44 | v3 ^= v0; \ 45 | v2 += v1; \ 46 | v1 = ROTL64(v1, 17); \ 47 | v1 ^= v2; \ 48 | v2 = ROTL64(v2, 32); \ 49 | } while (0) 50 | 51 | int siphash24(unsigned char *out, const unsigned char *in, 52 | unsigned long long inlen, const unsigned char *k) 53 | { 54 | /* "somepseudorandomlygeneratedbytes" */ 55 | uint64_t v0 = 0x736f6d6570736575ULL; 56 | uint64_t v1 = 0x646f72616e646f6dULL; 57 | uint64_t v2 = 0x6c7967656e657261ULL; 58 | uint64_t v3 = 0x7465646279746573ULL; 59 | uint64_t b; 60 | uint64_t k0 = LOAD64_LE(k); 61 | uint64_t k1 = LOAD64_LE(k + 8); 62 | uint64_t m; 63 | const uint8_t *end = in + inlen - (inlen % sizeof(uint64_t)); 64 | const int left = inlen & 7; 65 | 66 | b = ((uint64_t) inlen) << 56; 67 | v3 ^= k1; 68 | v2 ^= k0; 69 | v1 ^= k1; 70 | v0 ^= k0; 71 | for (; in != end; in += 8) { 72 | m = LOAD64_LE(in); 73 | v3 ^= m; 74 | SIPROUND; 75 | SIPROUND; 76 | v0 ^= m; 77 | } 78 | switch (left) { 79 | case 7: 80 | b |= ((uint64_t) in[6]) << 48; 81 | /* FALLTHRU */ 82 | case 6: 83 | b |= ((uint64_t) in[5]) << 40; 84 | /* FALLTHRU */ 85 | case 5: 86 | b |= ((uint64_t) in[4]) << 32; 87 | /* FALLTHRU */ 88 | case 4: 89 | b |= ((uint64_t) in[3]) << 24; 90 | /* FALLTHRU */ 91 | case 3: 92 | b |= ((uint64_t) in[2]) << 16; 93 | /* FALLTHRU */ 94 | case 2: 95 | b |= ((uint64_t) in[1]) << 8; 96 | /* FALLTHRU */ 97 | case 1: 98 | b |= ((uint64_t) in[0]); 99 | break; 100 | case 0: 101 | break; 102 | } 103 | v3 ^= b; 104 | SIPROUND; 105 | SIPROUND; 106 | v0 ^= b; 107 | v2 ^= 0xff; 108 | SIPROUND; 109 | SIPROUND; 110 | SIPROUND; 111 | SIPROUND; 112 | b = v0 ^ v1 ^ v2 ^ v3; 113 | STORE64_LE(out, b); 114 | 115 | return 0; 116 | } 117 | -------------------------------------------------------------------------------- /src/siphash24.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Extracted (and adjusted) from the Sodium library v1.0.16 3 | * https://libsodium.org 4 | */ 5 | 6 | #ifndef SIPHASH24_H 7 | #define SIPHASH24_H 8 | 9 | #define siphash24_BYTES 8U 10 | #define siphash24_KEYBYTES 16U 11 | 12 | int siphash24(unsigned char *out, const unsigned char *in, 13 | unsigned long long inlen, const unsigned char *k); 14 | 15 | #endif /* OWL_SIPHASH24_H */ 16 | -------------------------------------------------------------------------------- /src/state.c: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "version.h" 24 | #include "state.h" 25 | 26 | #define ETHER_BROADCAST (struct ether_addr) {{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }} 27 | #define PSF_INTERVAL_MASTER_TU 110 28 | #define PSF_INTERVAL_SLAVE_TU 440 29 | 30 | void awdl_init_state(struct awdl_state *state, const char *hostname, const struct ether_addr *self, 31 | struct awdl_chan chan, uint64_t now) { 32 | state->self_address = *self; 33 | strncpy(state->name, hostname, HOST_NAME_LENGTH_MAX); 34 | state->version = awdl_version(3, 4); 35 | state->dev_class = AWDL_DEVCLASS_MACOS; 36 | 37 | state->sequence_number = 0; 38 | state->psf_interval = PSF_INTERVAL_MASTER_TU; 39 | state->dst = ETHER_BROADCAST; 40 | 41 | state->tlv_cb = 0; 42 | state->tlv_cb_data = 0; 43 | 44 | state->peer_cb = 0; 45 | state->peer_cb_data = 0; 46 | 47 | state->peer_remove_cb = 0; 48 | state->peer_remove_cb_data = 0; 49 | 50 | state->filter_rssi = 1; 51 | state->rssi_threshold = RSSI_THRESHOLD_DEFAULT; 52 | state->rssi_grace = RSSI_GRACE_DEFAULT; 53 | 54 | awdl_sync_state_init(&state->sync, now); 55 | 56 | state->channel.enc = AWDL_CHAN_ENC_OPCLASS; 57 | state->channel.master = chan; 58 | state->channel.current = CHAN_NULL; 59 | //awdl_chanseq_init(state->channel.sequence); 60 | awdl_chanseq_init_static(state->channel.sequence, &state->channel.master); 61 | 62 | awdl_election_state_init(&state->election, self); 63 | 64 | awdl_peer_state_init(&state->peers); 65 | 66 | awdl_stats_init(&state->stats); 67 | } 68 | 69 | void awdl_stats_init(struct awdl_stats *stats) { 70 | stats->tx_action = 0; 71 | stats->tx_data = 0; 72 | stats->tx_data_unicast = 0; 73 | stats->tx_data_multicast = 0; 74 | stats->rx_action = 0; 75 | stats->rx_data = 0; 76 | stats->rx_unknown = 0; 77 | } 78 | 79 | uint16_t awdl_state_next_sequence_number(struct awdl_state *state) { 80 | return state->sequence_number++; 81 | }; 82 | 83 | void ieee80211_init_state(struct ieee80211_state *state) { 84 | state->sequence_number = 0; 85 | state->fcs = 0; 86 | } 87 | 88 | unsigned int ieee80211_state_next_sequence_number(struct ieee80211_state *state) { 89 | uint16_t seq = state->sequence_number; 90 | state->sequence_number += 1; 91 | state->sequence_number &= 0x0fff; /* seq has only 12 bits */ 92 | return seq; 93 | }; 94 | 95 | uint64_t clock_time_us() { 96 | int result; 97 | struct timespec now; 98 | uint64_t now_us = 0; 99 | 100 | result = clock_gettime(CLOCK_MONOTONIC, &now); 101 | if (!result) { 102 | /* TODO why using 'long' for time? */ 103 | now_us = now.tv_sec * 1000000; 104 | now_us += now.tv_nsec / 1000; 105 | } 106 | return now_us; 107 | } 108 | -------------------------------------------------------------------------------- /src/state.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #ifndef AWDL_STATE_H_ 21 | #define AWDL_STATE_H_ 22 | 23 | #include 24 | #include 25 | 26 | #include "wire.h" 27 | #include "frame.h" 28 | #include "peers.h" 29 | #include "sync.h" 30 | #include "channel.h" 31 | 32 | #define RSSI_THRESHOLD_DEFAULT -65 33 | #define RSSI_GRACE_DEFAULT -5 34 | 35 | struct awdl_state; /* forward declaration for tlv_cb */ 36 | 37 | typedef void (*awdl_tlv_cb)(struct awdl_peer *, uint8_t, const struct buf *, struct awdl_state *, void *); 38 | 39 | struct awdl_stats { 40 | uint64_t tx_action; 41 | uint64_t tx_data; 42 | uint64_t tx_data_unicast; 43 | uint64_t tx_data_multicast; 44 | uint64_t rx_action; 45 | uint64_t rx_data; 46 | uint64_t rx_unknown; 47 | }; 48 | 49 | /* Complete node state */ 50 | struct awdl_state { 51 | struct ether_addr self_address; 52 | char name[HOST_NAME_LENGTH_MAX + 1]; 53 | 54 | uint8_t version; 55 | uint8_t dev_class; 56 | 57 | /* sequence number for data frames */ 58 | uint16_t sequence_number; 59 | /* PSF interval (in TU) */ 60 | uint16_t psf_interval; 61 | /* destination address for action frames */ 62 | struct ether_addr dst; 63 | 64 | /* Allows to hook TLV reception */ 65 | awdl_tlv_cb tlv_cb; 66 | void *tlv_cb_data; 67 | 68 | /* Allows to hook adding of new neighbor */ 69 | awdl_peer_cb peer_cb; 70 | void *peer_cb_data; 71 | 72 | /* Allows to hook removing of new neighbor */ 73 | awdl_peer_cb peer_remove_cb; 74 | void *peer_remove_cb_data; 75 | 76 | int filter_rssi; /* whether or not to filter (default: true) */ 77 | signed char rssi_threshold; /* peers exceeding this threshold are discovered */ 78 | signed char rssi_grace; /* once discovered accept lower RSSI */ 79 | 80 | struct awdl_election_state election; 81 | struct awdl_sync_state sync; 82 | struct awdl_channel_state channel; 83 | struct awdl_peer_state peers; 84 | struct awdl_stats stats; 85 | }; 86 | 87 | void awdl_stats_init(struct awdl_stats *stats); 88 | 89 | void awdl_init_state(struct awdl_state *state, const char *hostname, const struct ether_addr *self, 90 | struct awdl_chan chan, uint64_t now); 91 | 92 | uint16_t awdl_state_next_sequence_number(struct awdl_state *); 93 | 94 | struct ieee80211_state { 95 | /* IEEE 802.11 sequence number */ 96 | uint16_t sequence_number; 97 | /* whether we need to add an fcs */ 98 | bool fcs; 99 | }; 100 | 101 | void ieee80211_init_state(struct ieee80211_state *); 102 | 103 | unsigned int ieee80211_state_next_sequence_number(struct ieee80211_state *); 104 | 105 | uint64_t clock_time_us(); 106 | 107 | #endif /* AWDL_STATE_H_ */ 108 | -------------------------------------------------------------------------------- /src/sync.c: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #include "sync.h" 21 | #include "ieee80211.h" 22 | 23 | void awdl_sync_state_init(struct awdl_sync_state *state, uint64_t now) { 24 | state->last_update = now; 25 | state->aw_counter = 0; 26 | state->aw_period = 16; 27 | state->presence_mode = 4; 28 | 29 | state->meas_err = 0; 30 | state->meas_total = 0; 31 | } 32 | 33 | uint16_t awdl_sync_next_aw_tu(uint64_t now_usec, const struct awdl_sync_state *state) { 34 | uint64_t eaw_period = state->presence_mode * state->aw_period; 35 | uint64_t time_since = ieee80211_usec_to_tu(now_usec - state->last_update); 36 | uint64_t next_aw_tu = eaw_period - (time_since % eaw_period); 37 | return (uint16_t) next_aw_tu; 38 | } 39 | 40 | uint64_t awdl_sync_next_aw_us(uint64_t now_usec, const struct awdl_sync_state *state) { 41 | uint64_t eaw_period = ieee80211_tu_to_usec(state->presence_mode * state->aw_period); 42 | uint64_t time_since = now_usec - state->last_update; 43 | uint64_t next_aw_us = eaw_period - (time_since % eaw_period); 44 | return next_aw_us; 45 | } 46 | 47 | uint16_t awdl_sync_current_aw(uint64_t now_usec, const struct awdl_sync_state *state) { 48 | uint64_t eaw_period = state->presence_mode * state->aw_period; 49 | uint64_t time_since = ieee80211_usec_to_tu(now_usec - state->last_update); 50 | uint64_t current_aw = state->aw_counter + /* last counter */ 51 | (time_since % eaw_period) / state->aw_period + /* within EAW */ 52 | state->presence_mode * (time_since / eaw_period); /* correction for EAWs */ 53 | return (uint16_t) current_aw; 54 | }; 55 | 56 | uint16_t awdl_sync_current_eaw(uint64_t now_usec, const struct awdl_sync_state *state) { 57 | return (awdl_sync_current_aw(now_usec, state) / state->presence_mode); 58 | } 59 | 60 | int64_t awdl_sync_error_tu(uint64_t now_usec, uint16_t time_to_next_aw, uint16_t aw_counter, 61 | const struct awdl_sync_state *state) { 62 | return ((aw_counter / state->presence_mode - awdl_sync_current_eaw(now_usec, state)) * 63 | state->presence_mode * state->aw_period) - 64 | (time_to_next_aw - awdl_sync_next_aw_tu(now_usec, state)); 65 | } 66 | 67 | void awdl_sync_update_last(uint64_t now_usec, uint16_t time_to_next_aw, uint16_t aw_counter, 68 | struct awdl_sync_state *state) { 69 | uint64_t eaw_period = state->presence_mode * state->aw_period; 70 | state->last_update = now_usec - ieee80211_tu_to_usec(eaw_period - time_to_next_aw); 71 | state->aw_counter = aw_counter & 0xfffc; /* mask last two bits, effectively 'aw_counter/4*4' */ 72 | } 73 | -------------------------------------------------------------------------------- /src/sync.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #ifndef AWDL_SYNC_H_ 21 | #define AWDL_SYNC_H_ 22 | 23 | #include 24 | 25 | struct awdl_sync_state { 26 | uint16_t aw_counter; 27 | uint64_t last_update; /* in us */ 28 | uint16_t aw_period; /* in TU */ 29 | uint8_t presence_mode; 30 | 31 | /* statistics */ 32 | uint64_t meas_err; 33 | uint64_t meas_total; 34 | }; 35 | 36 | void awdl_sync_state_init(struct awdl_sync_state *state, uint64_t now); 37 | 38 | uint16_t awdl_sync_next_aw_tu(uint64_t now_usec, const struct awdl_sync_state *state); 39 | 40 | uint64_t awdl_sync_next_aw_us(uint64_t now_usec, const struct awdl_sync_state *state); 41 | 42 | uint16_t awdl_sync_current_aw(uint64_t now_usec, const struct awdl_sync_state *state); 43 | 44 | uint16_t awdl_sync_current_eaw(uint64_t now_usec, const struct awdl_sync_state *state); 45 | 46 | int64_t awdl_sync_error_tu(uint64_t now_usec, uint16_t time_to_next_aw, uint16_t aw_counter, 47 | const struct awdl_sync_state *state); 48 | 49 | void awdl_sync_update_last(uint64_t now_usec, uint16_t time_to_next_aw, uint16_t aw_counter, 50 | struct awdl_sync_state *state); 51 | 52 | #endif /* AWDL_SYNC_H_ */ 53 | -------------------------------------------------------------------------------- /src/tx.c: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include "tx.h" 26 | #include "sync.h" 27 | #include "ieee80211.h" 28 | 29 | #include "crc32.h" 30 | 31 | #define AWDL_DNS_SHORT_LOCAL 0xc00c /* .local */ 32 | 33 | #define AWDL_DATA_HEAD 0x0403 34 | #define AWDL_DATA_PAD 0x0000 35 | 36 | #define AWDL_SOCIAL_CHANNEL_6_BIT 0x0001 37 | #define AWDL_SOCIAL_CHANNEL_44_BIT 0x0002 38 | #define AWDL_SOCIAL_CHANNEL_149_BIT 0x0004 39 | 40 | int awdl_init_data(uint8_t *buf, struct awdl_state *state) { 41 | struct awdl_data *header = (struct awdl_data *) buf; 42 | 43 | header->head = htole16(AWDL_DATA_HEAD); 44 | header->seq = htole16(awdl_state_next_sequence_number(state)); 45 | header->pad = htole16(AWDL_DATA_PAD); 46 | /* TODO we should generally to able to send any kind of data */ 47 | header->ethertype = htobe16(ETH_P_IPV6); 48 | 49 | return sizeof(struct awdl_data); 50 | } 51 | 52 | int awdl_init_action(uint8_t *buf, enum awdl_action_type type) { 53 | struct awdl_action *af = (struct awdl_action *) buf; 54 | 55 | uint32_t steady_time = (uint32_t) clock_time_us(); /* TODO awdl_init_* methods should not call clock_time_us() themselves but rather be given as parameter to avoid inconsistent calculation of stuff, e.g., fields in sync parameters should be calculated based on the timestamp indicated in af->target_tx */ 56 | af->category = IEEE80211_VENDOR_SPECIFIC; /* vendor specific */ 57 | af->oui = AWDL_OUI; 58 | af->type = AWDL_TYPE; 59 | af->version = AWDL_VERSION_COMPAT; 60 | af->subtype = type; 61 | af->reserved = 0; 62 | af->phy_tx = htole32(steady_time); /* TODO arbitrary offset */ 63 | af->target_tx = htole32(steady_time); 64 | 65 | return sizeof(struct awdl_action); 66 | } 67 | 68 | int awdl_chan_encoding_length(enum awdl_chan_encoding enc) { 69 | switch (enc) { 70 | case AWDL_CHAN_ENC_SIMPLE: 71 | return 1; 72 | case AWDL_CHAN_ENC_LEGACY: 73 | case AWDL_CHAN_ENC_OPCLASS: 74 | return 2; 75 | default: 76 | return 0; /* unknown encoding */ 77 | } 78 | } 79 | 80 | int awdl_init_chanseq(uint8_t *buf, const struct awdl_state *state) { 81 | struct awdl_chanseq *chanseq = (struct awdl_chanseq *) buf; 82 | int enc_len = awdl_chan_encoding_length(state->channel.enc); 83 | int offset = sizeof(struct awdl_chanseq); 84 | 85 | chanseq->count = AWDL_CHANSEQ_LENGTH - 1; /* +1 */ 86 | chanseq->encoding = state->channel.enc; 87 | chanseq->duplicate_count = 0; 88 | chanseq->step_count = 3; 89 | chanseq->fill_channel = htole16(0xffff); /* repeat current channel */ 90 | for (int i = 0; i < AWDL_CHANSEQ_LENGTH; i++) { 91 | /* copy based on length */ 92 | memcpy(buf + offset, &(state->channel.sequence[i]), enc_len); 93 | offset += enc_len; 94 | } 95 | return offset; 96 | } 97 | 98 | int awdl_init_sync_params_tlv(uint8_t *buf, const struct awdl_state *state) { 99 | struct awdl_sync_params_tlv *tlv = (struct awdl_sync_params_tlv *) buf; 100 | int len; 101 | uint64_t now; 102 | 103 | now = clock_time_us(); 104 | 105 | tlv->type = AWDL_SYNCHRONIZATON_PARAMETERS_TLV; 106 | 107 | /* static info: appears to be fixed in current AWDL implementation */ 108 | tlv->guard_time = 0; 109 | tlv->aw_period = htole16(state->sync.aw_period); 110 | tlv->aw_ext_length = htole16(state->sync.aw_period); 111 | tlv->aw_com_length = htole16(state->sync.aw_period); 112 | tlv->min_ext = state->sync.presence_mode - 1; 113 | tlv->max_ext_unicast = state->sync.presence_mode - 1; 114 | tlv->max_ext_multicast = state->sync.presence_mode - 1; 115 | tlv->max_ext_af = state->sync.presence_mode - 1; 116 | 117 | tlv->flags = htole16(0x1800); /* TODO: not sure what they do */ 118 | 119 | tlv->reserved = 0; 120 | 121 | /* TODO: dynamic info needs to be adjusted during runtime */ 122 | tlv->next_aw_channel = awdl_chan_num(state->channel.current, 123 | state->channel.enc); /* TODO need to calculate this from current seq */ 124 | tlv->next_aw_seq = htole16(awdl_sync_current_aw(now, &state->sync)); 125 | tlv->ap_alignment = tlv->next_aw_seq; /* awdl_fill_sync_params(..) */ 126 | tlv->tx_down_counter = htole16(awdl_sync_next_aw_tu(now, &state->sync)); 127 | tlv->af_period = htole16(state->psf_interval); 128 | tlv->presence_mode = state->sync.presence_mode; /* always available, usually 4 */ 129 | tlv->master_addr = state->election.master_addr; 130 | tlv->master_channel = awdl_chan_num(state->channel.master, state->channel.enc); 131 | /* lower bound is 0 */ 132 | if (le16toh(tlv->aw_com_length) < (le16toh(tlv->aw_period) * tlv->presence_mode - le16toh(tlv->tx_down_counter))) 133 | tlv->remaining_aw_length = htole16(0); 134 | else 135 | tlv->remaining_aw_length = htole16(le16toh(tlv->aw_com_length) - 136 | (le16toh(tlv->aw_period) * tlv->presence_mode - le16toh(tlv->tx_down_counter))); 137 | 138 | len = sizeof(struct awdl_sync_params_tlv); 139 | len += awdl_init_chanseq(buf + sizeof(struct awdl_sync_params_tlv), state); 140 | /* padding */ 141 | buf[len++] = 0; 142 | buf[len++] = 0; 143 | 144 | tlv->length = htole16(len - sizeof(struct tl)); 145 | 146 | return len; 147 | } 148 | 149 | int awdl_init_chanseq_tlv(uint8_t *buf, const struct awdl_state *state) { 150 | struct awdl_chanseq_tlv *tlv = (struct awdl_chanseq_tlv *) buf; 151 | int len; 152 | 153 | tlv->type = AWDL_CHAN_SEQ_TLV; 154 | 155 | len = sizeof(struct awdl_chanseq_tlv); 156 | len += awdl_init_chanseq(buf + sizeof(struct awdl_chanseq_tlv), state); 157 | /* padding */ 158 | buf[len++] = 0; 159 | buf[len++] = 0; 160 | buf[len++] = 0; 161 | tlv->length = htole16(len - sizeof(struct tl)); 162 | 163 | return len; 164 | } 165 | 166 | int awdl_init_election_params_tlv(uint8_t *buf, const struct awdl_state *state) { 167 | struct awdl_election_params_tlv *tlv = (struct awdl_election_params_tlv *) buf; 168 | 169 | tlv->type = AWDL_ELECTION_PARAMETERS_TLV; 170 | tlv->length = htole16(sizeof(struct awdl_election_params_tlv) - sizeof(struct tl)); 171 | 172 | tlv->distancetop = state->election.height; 173 | tlv->top_master_addr = state->election.master_addr; 174 | tlv->top_master_metric = htole32(state->election.master_metric); 175 | tlv->self_metric = htole32(state->election.self_metric); 176 | 177 | /* TODO unsure what flags do */ 178 | tlv->flags = 0; 179 | tlv->id = htole16(0); 180 | 181 | tlv->unknown = 0; 182 | tlv->pad[0] = 0; 183 | tlv->pad[1] = 0; 184 | 185 | return sizeof(struct awdl_election_params_tlv); 186 | } 187 | 188 | int awdl_init_election_params_v2_tlv(uint8_t *buf, const struct awdl_state *state) { 189 | struct awdl_election_params_v2_tlv *tlv = (struct awdl_election_params_v2_tlv *) buf; 190 | 191 | tlv->type = AWDL_ELECTION_PARAMETERS_V2_TLV; 192 | tlv->length = htole16(sizeof(struct awdl_election_params_v2_tlv) - sizeof(struct tl)); 193 | 194 | tlv->master_addr = state->election.master_addr; 195 | tlv->sync_addr = state->election.sync_addr; 196 | tlv->distance_to_master = htole32(state->election.height); 197 | tlv->master_metric = htole32(state->election.master_metric); 198 | tlv->self_metric = htole32(state->election.self_metric); 199 | tlv->unknown = htole32(0); 200 | tlv->reserved = htole32(0); 201 | 202 | tlv->master_counter = htole32(state->election.master_counter); 203 | tlv->self_counter = htole32(state->election.self_counter); 204 | 205 | return sizeof(struct awdl_election_params_v2_tlv); 206 | } 207 | 208 | int awdl_init_service_params_tlv(uint8_t *buf, const struct awdl_state *state __attribute__((unused))) { 209 | struct awdl_service_params_tlv *tlv = (struct awdl_service_params_tlv *) buf; 210 | 211 | tlv->type = AWDL_SERVICE_PARAMETERS_TLV; 212 | tlv->length = htole16(sizeof(struct awdl_service_params_tlv) - sizeof(struct tl)); 213 | 214 | /* changing the SUI causes receiving nodes to flush their mDNS cache, 215 | * other than that, this TLV seems to be deprecated in AWDL v2+ */ 216 | 217 | tlv->unknown[0] = 0; 218 | tlv->unknown[1] = 0; 219 | tlv->unknown[2] = 0; 220 | tlv->sui = htole16(0); 221 | tlv->bitmask = htole32(0); 222 | 223 | return sizeof(struct awdl_service_params_tlv); 224 | } 225 | 226 | int awdl_init_ht_capabilities_tlv(uint8_t *buf, const struct awdl_state *state __attribute__((unused))) { 227 | struct awdl_ht_capabilities_tlv *tlv = (struct awdl_ht_capabilities_tlv *) buf; 228 | 229 | tlv->type = AWDL_ENHANCED_DATA_RATE_CAPABILITIES_TLV; 230 | tlv->length = htole16(sizeof(struct awdl_ht_capabilities_tlv) - sizeof(struct tl)); 231 | 232 | /* TODO extract capabilities from nl80211 (nl80211_band_attr) */ 233 | tlv->ht_capabilities = htole16(0x11ce); 234 | tlv->ampdu_params = 0x1b; 235 | tlv->rx_mcs = 0xff; /* one stream, all MCS */ 236 | 237 | tlv->unknown = htole16(0); 238 | tlv->unknown2 = htole16(0); 239 | 240 | return sizeof(struct awdl_ht_capabilities_tlv); 241 | } 242 | 243 | int awdl_init_data_path_state_tlv(uint8_t *buf, const struct awdl_state *state) { 244 | struct awdl_data_path_state_tlv *tlv = (struct awdl_data_path_state_tlv *) buf; 245 | 246 | tlv->type = AWDL_DATA_PATH_STATE_TLV; 247 | tlv->length = htole16(sizeof(struct awdl_data_path_state_tlv) - sizeof(struct tl)); 248 | 249 | /* TODO this is very ugly currently */ 250 | tlv->flags = htole16(0x8f24); 251 | 252 | tlv->awdl_addr = state->self_address; 253 | 254 | tlv->country_code[0] = 'X'; 255 | tlv->country_code[1] = '0'; 256 | tlv->country_code[2] = 0; 257 | 258 | if (awdl_chan_num(state->channel.master, AWDL_CHAN_ENC_OPCLASS) == 6) 259 | tlv->social_channels = htole16(AWDL_SOCIAL_CHANNEL_6_BIT); 260 | else if (awdl_chan_num(state->channel.master, AWDL_CHAN_ENC_OPCLASS) == 44) { 261 | tlv->social_channels = htole16(AWDL_SOCIAL_CHANNEL_44_BIT); 262 | } else { // 149 263 | tlv->social_channels = htole16(AWDL_SOCIAL_CHANNEL_149_BIT); 264 | } 265 | 266 | tlv->ext_flags = htole16(0x0000); 267 | 268 | return sizeof(struct awdl_data_path_state_tlv); 269 | } 270 | 271 | int awdl_init_arpa_tlv(uint8_t *buf, const struct awdl_state *state) { 272 | struct awdl_arpa_tlv *tlv = (struct awdl_arpa_tlv *) buf; 273 | size_t len = strlen(state->name); 274 | 275 | tlv->type = AWDL_ARPA_TLV; 276 | tlv->length = htole16((uint16_t) (sizeof(struct awdl_arpa_tlv) - sizeof(struct tl) + len + 1)); 277 | 278 | tlv->flags = 3; 279 | tlv->name_length = (uint8_t) len; 280 | memcpy(tlv->name, state->name, len); 281 | *(uint16_t *) (tlv->name + len) = htobe16(AWDL_DNS_SHORT_LOCAL); 282 | 283 | return sizeof(struct tl) + le16toh(tlv->length); 284 | } 285 | 286 | int awdl_init_version_tlv(uint8_t *buf, const struct awdl_state *state) { 287 | struct awdl_version_tlv *tlv = (struct awdl_version_tlv *) buf; 288 | 289 | tlv->type = AWDL_VERSION_TLV; 290 | tlv->length = htole16(sizeof(struct awdl_version_tlv) - sizeof(struct tl)); 291 | tlv->version = state->version; 292 | tlv->devclass = state->dev_class; 293 | 294 | return sizeof(struct awdl_version_tlv); 295 | } 296 | 297 | int ieee80211_init_radiotap_header(uint8_t *buf) { 298 | /* 299 | * TX radiotap headers and mac80211 300 | * https://www.kernel.org/doc/Documentation/networking/mac80211-injection.txt 301 | */ 302 | struct ieee80211_radiotap_header *hdr = (struct ieee80211_radiotap_header *) buf; 303 | uint8_t *ptr = buf + sizeof(struct ieee80211_radiotap_header); 304 | uint32_t present = 0; 305 | 306 | hdr->it_version = 0; 307 | hdr->it_pad = 0; 308 | 309 | /* TODO Adjust PHY parameters based on receiver capabilities */ 310 | 311 | present |= ieee80211_radiotap_type_to_mask(IEEE80211_RADIOTAP_RATE); 312 | *ptr = htole16(ieee80211_radiotap_rate_to_val(12)); 313 | ptr += sizeof(uint8_t); 314 | 315 | hdr->it_len = htole16((uint16_t) (ptr - buf)); 316 | hdr->it_present = htole32(present); 317 | 318 | return ptr - buf; 319 | } 320 | 321 | int ieee80211_init_awdl_hdr(uint8_t *buf, const struct ether_addr *src, const struct ether_addr *dst, 322 | struct ieee80211_state *state, uint16_t type) { 323 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) buf; 324 | 325 | hdr->frame_control = htole16(type); 326 | hdr->duration_id = htole16(0); 327 | hdr->addr1 = *dst; 328 | hdr->addr2 = *src; 329 | hdr->addr3 = AWDL_BSSID; 330 | hdr->seq_ctrl = htole16(ieee80211_state_next_sequence_number(state) << 4); 331 | 332 | return sizeof(struct ieee80211_hdr); 333 | } 334 | 335 | int ieee80211_init_awdl_action_hdr(uint8_t *buf, const struct ether_addr *src, const struct ether_addr *dst, 336 | struct ieee80211_state *state) { 337 | return ieee80211_init_awdl_hdr(buf, src, dst, state, IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); 338 | } 339 | 340 | int ieee80211_init_awdl_data_hdr(uint8_t *buf, const struct ether_addr *src, const struct ether_addr *dst, 341 | struct ieee80211_state *state) { 342 | return ieee80211_init_awdl_hdr(buf, src, dst, state, IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); 343 | } 344 | 345 | int llc_init_awdl_hdr(uint8_t *buf) { 346 | struct llc_hdr *hdr = (struct llc_hdr *) buf; 347 | 348 | hdr->dsap = 0xaa; /* 0xaa - SNAP Extension Used */ 349 | hdr->ssap = 0xaa; /* 0xaa - SNAP Extension Used */ 350 | hdr->control = 0x03; 351 | hdr->oui = AWDL_OUI; 352 | hdr->pid = htobe16(AWDL_LLC_PROTOCOL_ID); 353 | 354 | return sizeof(struct llc_hdr); 355 | } 356 | 357 | int ieee80211_add_fcs(const uint8_t *start, uint8_t *end) { 358 | uint32_t crc = crc32(start, end - start); 359 | *(uint32_t *) end = htole32(crc); 360 | return sizeof(uint32_t); 361 | } 362 | 363 | int awdl_init_full_action_frame(uint8_t *buf, struct awdl_state *state, struct ieee80211_state *ieee80211_state, 364 | enum awdl_action_type type) { 365 | uint8_t *ptr = buf; 366 | 367 | ptr += ieee80211_init_radiotap_header(ptr); 368 | ptr += ieee80211_init_awdl_action_hdr(ptr, &state->self_address, &state->dst, ieee80211_state); 369 | ptr += awdl_init_action(ptr, type); 370 | ptr += awdl_init_sync_params_tlv(ptr, state); 371 | ptr += awdl_init_election_params_tlv(ptr, state); 372 | ptr += awdl_init_chanseq_tlv(ptr, state); 373 | ptr += awdl_init_election_params_v2_tlv(ptr, state); 374 | ptr += awdl_init_service_params_tlv(ptr, state); 375 | if (type == AWDL_ACTION_MIF) 376 | ptr += awdl_init_ht_capabilities_tlv(ptr, state); 377 | if (type == AWDL_ACTION_MIF) 378 | ptr += awdl_init_arpa_tlv(ptr, state); 379 | ptr += awdl_init_data_path_state_tlv(ptr, state); 380 | ptr += awdl_init_version_tlv(ptr, state); 381 | if (ieee80211_state->fcs) 382 | ptr += ieee80211_add_fcs(buf, ptr); 383 | 384 | return ptr - buf; 385 | } 386 | 387 | int awdl_init_full_data_frame(uint8_t *buf, const struct ether_addr *src, const struct ether_addr *dst, 388 | const uint8_t *payload, unsigned int plen, 389 | struct awdl_state *state, struct ieee80211_state *ieee80211_state) { 390 | uint8_t *ptr = buf; 391 | 392 | ptr += ieee80211_init_radiotap_header(ptr); 393 | ptr += ieee80211_init_awdl_data_hdr(ptr, src, dst, ieee80211_state); 394 | ptr += llc_init_awdl_hdr(ptr); 395 | ptr += awdl_init_data(ptr, state); 396 | memcpy(ptr, payload, plen); 397 | ptr += plen; 398 | if (ieee80211_state->fcs) 399 | ptr += ieee80211_add_fcs(buf, ptr); 400 | 401 | return ptr - buf; 402 | } 403 | -------------------------------------------------------------------------------- /src/tx.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #ifndef AWDL_TX_H_ 21 | #define AWDL_TX_H_ 22 | 23 | #include "frame.h" 24 | #include "version.h" 25 | #include "state.h" 26 | 27 | enum TX_RESULT { 28 | TX_OK = 0, 29 | TX_FAIL = -1, 30 | }; 31 | 32 | int awdl_init_action(uint8_t *buf, enum awdl_action_type); 33 | 34 | int awdl_init_chanseq(uint8_t *buf, const struct awdl_state *); 35 | 36 | int awdl_init_sync_params_tlv(uint8_t *buf, const struct awdl_state *); 37 | 38 | int awdl_init_chanseq_tlv(uint8_t *buf, const struct awdl_state *); 39 | 40 | int awdl_init_election_params_tlv(uint8_t *buf, const struct awdl_state *); 41 | 42 | int awdl_init_election_params_v2_tlv(uint8_t *buf, const struct awdl_state *); 43 | 44 | int awdl_init_service_params_tlv(uint8_t *buf, const struct awdl_state *); 45 | 46 | int awdl_init_ht_capabilities_tlv(uint8_t *buf, const struct awdl_state *); 47 | 48 | int awdl_init_data_path_state_tlv(uint8_t *buf, const struct awdl_state *); 49 | 50 | int awdl_init_arpa_tlv(uint8_t *buf, const struct awdl_state *); 51 | 52 | int awdl_init_version_tlv(uint8_t *buf, const struct awdl_state *); 53 | 54 | int awdl_init_full_action_frame(uint8_t *buf, struct awdl_state *, struct ieee80211_state *, enum awdl_action_type); 55 | 56 | int awdl_init_data(uint8_t *buf, struct awdl_state *); 57 | 58 | int awdl_init_full_data_frame(uint8_t *buf, const struct ether_addr *src, const struct ether_addr *dst, 59 | const uint8_t *payload, unsigned int plen, 60 | struct awdl_state *, struct ieee80211_state *); 61 | 62 | int ieee80211_init_radiotap_header(uint8_t *buf); 63 | 64 | int ieee80211_init_awdl_hdr(uint8_t *buf, const struct ether_addr *src, const struct ether_addr *dst, 65 | struct ieee80211_state *, uint16_t type); 66 | 67 | int ieee80211_init_awdl_action_hdr(uint8_t *buf, const struct ether_addr *src, const struct ether_addr *dst, 68 | struct ieee80211_state *); 69 | 70 | int ieee80211_init_awdl_data_hdr(uint8_t *buf, const struct ether_addr *src, const struct ether_addr *dst, 71 | struct ieee80211_state *); 72 | 73 | int llc_init_awdl_hdr(uint8_t *buf); 74 | 75 | #endif /* AWDL_TX_H_ */ 76 | -------------------------------------------------------------------------------- /src/version.c: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | 22 | #include "version.h" 23 | 24 | uint8_t awdl_version(int major, int minor) { 25 | return ((uint8_t) (((major) << 4) & 0xf0) | ((minor) & 0x0f)); 26 | } 27 | 28 | int awdl_version_major(uint8_t version) { 29 | return (version >> 4) & 0xf; 30 | } 31 | 32 | int awdl_version_minor(uint8_t version) { 33 | return (version & 0xf); 34 | } 35 | 36 | const char *awdl_version_to_str(uint8_t version) { 37 | static char str[64]; 38 | char *cur = str, *const end = str + sizeof(str); 39 | cur += snprintf(cur, end - cur, "%d", awdl_version_major(version)); 40 | cur += snprintf(cur, end - cur, "."); 41 | cur += snprintf(cur, end - cur, "%d", awdl_version_minor(version)); 42 | return str; 43 | } 44 | 45 | const char *awdl_devclass_to_str(uint8_t devclass) { 46 | switch (devclass) { 47 | case AWDL_DEVCLASS_MACOS: 48 | return "macOS"; 49 | case AWDL_DEVCLASS_IOS: 50 | return "iOS"; 51 | case AWDL_DEVCLASS_TVOS: 52 | return "tvOS"; 53 | default: 54 | return "Unknown"; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #ifndef AWDL_VERSION_H_ 21 | #define AWDL_VERSION_H_ 22 | 23 | #include 24 | 25 | uint8_t awdl_version(int major, int minor); 26 | 27 | int awdl_version_major(uint8_t version); 28 | 29 | int awdl_version_minor(uint8_t version); 30 | 31 | const char *awdl_version_to_str(uint8_t); 32 | 33 | enum awdl_devclass { 34 | AWDL_DEVCLASS_MACOS = 1, 35 | AWDL_DEVCLASS_IOS = 2, 36 | AWDL_DEVCLASS_TVOS = 8, 37 | }; 38 | 39 | const char *awdl_devclass_to_str(uint8_t devclass); 40 | 41 | #endif /* AWDL_VERSION_H_ */ 42 | -------------------------------------------------------------------------------- /src/wire.c: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include "wire.h" 24 | 25 | struct buf { 26 | const uint8_t *orig; 27 | uint8_t *data; 28 | int len; 29 | int owned; 30 | }; 31 | 32 | struct buf *buf_new_owned(int len) { 33 | if (len < 0) 34 | return NULL; 35 | struct buf *buf = (struct buf *) malloc(sizeof(struct buf)); 36 | buf->data = (uint8_t *) malloc(len); 37 | buf->orig = buf->data; 38 | buf->len = len; 39 | buf->owned = 1; 40 | return buf; 41 | } 42 | 43 | const struct buf *buf_new_const(const uint8_t *data, int len) { 44 | if (len < 0) 45 | return NULL; 46 | struct buf *buf = (struct buf *) malloc(sizeof(struct buf)); 47 | buf->data = (uint8_t *) data; 48 | buf->orig = data; 49 | buf->len = len; 50 | buf->owned = 0; 51 | return buf; 52 | } 53 | 54 | void buf_free(const struct buf *buf) { 55 | if (buf->owned) 56 | free((void *) buf->orig); 57 | free((struct buf *) buf); 58 | } 59 | 60 | const uint8_t *buf_data(const struct buf *buf) { 61 | return buf->data; 62 | } 63 | 64 | int buf_len(const struct buf *buf) { 65 | return buf->len; 66 | } 67 | 68 | int buf_strip(const struct buf *buf, int len) { 69 | if (len > buf->len || len < 0) 70 | return OUT_OF_BOUNDS; 71 | ((struct buf *) buf)->data += len; 72 | ((struct buf *) buf)->len -= len; 73 | return len; 74 | } 75 | 76 | int buf_take(const struct buf *buf, int len) { 77 | if (len > buf->len || len < 0) 78 | return OUT_OF_BOUNDS; 79 | ((struct buf *) buf)->len -= len; 80 | return len; 81 | } 82 | 83 | int write_u8(struct buf *buf, int offset, uint8_t value) { 84 | if (offset < 0 || offset + 1 > buf->len) 85 | return OUT_OF_BOUNDS; 86 | *(buf->data + offset) = value; 87 | return 1; 88 | } 89 | 90 | int write_le16(struct buf *buf, int offset, uint16_t value) { 91 | if (offset < 0 || offset + 2 > buf->len) 92 | return OUT_OF_BOUNDS; 93 | *(uint16_t *) (buf->data + offset) = htole16(value); 94 | return 2; 95 | } 96 | 97 | int write_be16(struct buf *buf, int offset, uint16_t value) { 98 | if (offset < 0 || offset + 2 > buf->len) 99 | return OUT_OF_BOUNDS; 100 | *(uint16_t *) (buf->data + offset) = htobe16(value); 101 | return 2; 102 | } 103 | 104 | int write_le32(struct buf *buf, int offset, uint32_t value) { 105 | if (offset < 0 || offset + 4 > buf->len) 106 | return OUT_OF_BOUNDS; 107 | *(uint32_t *) (buf->data + offset) = htole32(value); 108 | return 4; 109 | } 110 | 111 | int write_be32(struct buf *buf, int offset, uint32_t value) { 112 | if (offset < 0 || offset + 4 > buf->len) 113 | return OUT_OF_BOUNDS; 114 | *(uint32_t *) (buf->data + offset) = htobe32(value); 115 | return 4; 116 | } 117 | 118 | int write_ether_addr(struct buf *buf, int offset, const struct ether_addr *addr) { 119 | if (offset < 0 || offset + ETHER_ADDR_LEN > buf->len) 120 | return OUT_OF_BOUNDS; 121 | *(struct ether_addr *) (buf->data + offset) = *addr; 122 | return ETHER_ADDR_LEN; 123 | } 124 | 125 | int write_bytes(struct buf *buf, int offset, const uint8_t *bytes, int length) { 126 | if (offset < 0 || offset + length > buf->len) 127 | return OUT_OF_BOUNDS; 128 | memcpy(buf->data + offset, bytes, length); 129 | return length; 130 | } 131 | 132 | int read_u8(const struct buf *buf, int offset, uint8_t *value) { 133 | if (offset < 0 || offset + 1 > buf->len) 134 | return OUT_OF_BOUNDS; 135 | if (value) 136 | *value = *(buf->data + offset); 137 | return 1; 138 | } 139 | 140 | int read_le16(const struct buf *buf, int offset, uint16_t *value) { 141 | if (offset < 0 || offset + 2 > buf->len) 142 | return OUT_OF_BOUNDS; 143 | if (value) 144 | *value = le16toh(*(uint16_t *) (buf->data + offset)); 145 | return 2; 146 | } 147 | 148 | int read_be16(const struct buf *buf, int offset, uint16_t *value) { 149 | if (offset < 0 || offset + 2 > buf->len) 150 | return OUT_OF_BOUNDS; 151 | if (value) 152 | *value = be16toh(*(uint16_t *) (buf->data + offset)); 153 | return 2; 154 | } 155 | 156 | int read_le32(const struct buf *buf, int offset, uint32_t *value) { 157 | if (offset < 0 || offset + 4 > buf->len) 158 | return OUT_OF_BOUNDS; 159 | if (value) 160 | *value = le32toh(*(uint32_t *) (buf->data + offset)); 161 | return 4; 162 | } 163 | 164 | int read_be32(const struct buf *buf, int offset, uint32_t *value) { 165 | if (offset < 0 || offset + 4 > buf->len) 166 | return OUT_OF_BOUNDS; 167 | if (value) 168 | *value = be32toh(*(uint32_t *) (buf->data + offset)); 169 | return 4; 170 | } 171 | 172 | int read_ether_addr(const struct buf *buf, int offset, struct ether_addr *addr) { 173 | if (offset < 0 || offset + ETHER_ADDR_LEN > buf->len) 174 | return OUT_OF_BOUNDS; 175 | if (addr) 176 | *addr = *(struct ether_addr *) (buf->data + offset); 177 | return ETHER_ADDR_LEN; 178 | } 179 | 180 | int read_bytes(const struct buf *buf, int offset, const uint8_t **bytes, int length) { 181 | if (offset < 0 || offset + length > buf->len) 182 | return OUT_OF_BOUNDS; 183 | if (bytes) 184 | *bytes = buf->data + offset; 185 | return length; 186 | } 187 | 188 | int read_bytes_copy(const struct buf *buf, int offset, uint8_t *bytes, int length) { 189 | if (offset < 0 || offset + length > buf->len) 190 | return OUT_OF_BOUNDS; 191 | if (bytes) 192 | memcpy(bytes, buf->data + offset, length); 193 | return length; 194 | } 195 | 196 | int read_int_string(const struct buf *buf, int offset, char *str, int length) { 197 | uint8_t _len; 198 | READ_U8(buf, offset, &_len); 199 | if (_len > length) 200 | _len = length; 201 | READ_BYTES_COPY(buf, offset + 1, (uint8_t *) str, _len); 202 | if (str) 203 | str[_len] = 0; /* add trailing zero */ 204 | return _len + 1; 205 | wire_error: 206 | return OUT_OF_BOUNDS; 207 | } 208 | 209 | int read_tlv(const struct buf *buf, int offset, uint8_t *type, uint16_t *len, const uint8_t **val) { 210 | uint8_t _type; 211 | uint16_t _len; 212 | READ_U8(buf, offset, &_type); 213 | READ_LE16(buf, offset + 1, &_len); 214 | READ_BYTES(buf, offset + 3, val, _len); 215 | if (type) 216 | *type = _type; 217 | if (len) 218 | *len = _len; 219 | return _len + 3; 220 | wire_error: 221 | return OUT_OF_BOUNDS; 222 | } 223 | -------------------------------------------------------------------------------- /src/wire.h: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | #ifndef OWL_WIRE_H 21 | #define OWL_WIRE_H 22 | 23 | #include 24 | #include 25 | 26 | #ifdef __APPLE__ 27 | 28 | #include 29 | #include 30 | 31 | #define htobe16(x) OSSwapHostToBigInt16(x) 32 | #define htole16(x) OSSwapHostToLittleInt16(x) 33 | #define be16toh(x) OSSwapBigToHostInt16(x) 34 | #define le16toh(x) OSSwapLittleToHostInt16(x) 35 | 36 | #define htobe32(x) OSSwapHostToBigInt32(x) 37 | #define htole32(x) OSSwapHostToLittleInt32(x) 38 | #define be32toh(x) OSSwapBigToHostInt32(x) 39 | #define le32toh(x) OSSwapLittleToHostInt32(x) 40 | 41 | #define htobe64(x) OSSwapHostToBigInt64(x) 42 | #define htole64(x) OSSwapHostToLittleInt64(x) 43 | #define be64toh(x) OSSwapBigToHostInt64(x) 44 | #define le64toh(x) OSSwapLittleToHostInt64(x) 45 | 46 | #else 47 | 48 | #include 49 | 50 | #endif /* __APPLE__ */ 51 | 52 | 53 | /** @brief Opaque buffer used to transport network packets. 54 | * 55 | * We can read from and write to a buffer using dedicated 56 | * read and write functions. 57 | * 58 | * @see buf_data 59 | * @see buf_len 60 | */ 61 | struct buf; 62 | 63 | /* TODO change interface: only return wire_error or 0, do not return length */ 64 | 65 | enum wire_error { 66 | OUT_OF_BOUNDS = -1, 67 | }; 68 | 69 | /** @brief Allocates a new {@code buf} of given length. 70 | * 71 | * Will free internal array when calling {@code buf_free}. 72 | * 73 | * @param len length of the buffer in bytes 74 | * @return a pointer to a mutable {@code buf} instance 75 | * 76 | * @see buf_new_const 77 | * @see buf_free 78 | */ 79 | struct buf *buf_new_owned(int len); 80 | 81 | /** @brief Allocates a new {@code buf} an already existing bytes array. 82 | * 83 | * Will use {@code data} as its internal array which is _not_ freed when calling {@code buf_free}. 84 | * 85 | * @param data immutable reference to buffer array 86 | * @param len length of the buffer in bytes 87 | * @return a pointer to a mutable {@code buf} instance 88 | * 89 | * @see buf_new_owned 90 | * @see buf_free 91 | */ 92 | const struct buf *buf_new_const(const uint8_t *data, int len); 93 | 94 | /** @brief Deallocates a {@code buf} instance. 95 | * 96 | * Will dellocate internal bytes array if {@code buf} is an 'owned' instance. 97 | * 98 | * @param buf instance to free 99 | * 100 | * @see buf_new_owned 101 | * @see buf_new_const 102 | */ 103 | void buf_free(const struct buf *buf); 104 | 105 | /** @brief Read-only access to internal bytes array. */ 106 | const uint8_t *buf_data(const struct buf *buf); 107 | 108 | /** @brief Length of internal bytes array. */ 109 | int buf_len(const struct buf *buf); 110 | 111 | #define BUF_STRIP(buf, len) \ 112 | do { \ 113 | int result = buf_strip(buf, len); \ 114 | if (result < 0) \ 115 | goto wire_error; \ 116 | } while (0) 117 | 118 | /** @brief Strip {@code len} bytes from the front of {@code buf}. 119 | * 120 | * @return 0 if successful or -1 if {@code len} is longer than length of {@code buf} 121 | */ 122 | int buf_strip(const struct buf *buf, int len); 123 | 124 | #define BUF_TAKE(buf, len) \ 125 | do { \ 126 | int result = buf_take(buf, len); \ 127 | if (result < 0) \ 128 | goto wire_error; \ 129 | } while (0) 130 | 131 | /** @brief Strip {@code len} bytes from the end of {@code buf}. 132 | * 133 | * @return 0 if successful or -1 if {@code len} is longer than length of {@code buf} 134 | */ 135 | int buf_take(const struct buf *buf, int len); 136 | 137 | int write_u8(struct buf *buf, int offset, uint8_t value); 138 | 139 | int write_le16(struct buf *buf, int offset, uint16_t value); 140 | 141 | int write_be16(struct buf *buf, int offset, uint16_t value); 142 | 143 | int write_le32(struct buf *buf, int offset, uint32_t value); 144 | 145 | int write_be32(struct buf *buf, int offset, uint32_t value); 146 | 147 | int write_ether_addr(struct buf *buf, int offset, const struct ether_addr *addr); 148 | 149 | int write_bytes(struct buf *buf, int offset, const uint8_t *bytes, int length); 150 | 151 | #define CHECKED_READ(type, ...) \ 152 | do { \ 153 | int result = read_##type(__VA_ARGS__); \ 154 | if (result < 0) \ 155 | goto wire_error; \ 156 | } while (0) 157 | 158 | #define READ_U8(...) CHECKED_READ(u8, __VA_ARGS__) 159 | #define READ_LE16(...) CHECKED_READ(le16, __VA_ARGS__) 160 | #define READ_BE16(...) CHECKED_READ(be16, __VA_ARGS__) 161 | #define READ_LE32(...) CHECKED_READ(le32, __VA_ARGS__) 162 | #define READ_BE32(...) CHECKED_READ(be32, __VA_ARGS__) 163 | #define READ_ETHER_ADDR(...) CHECKED_READ(ether_addr, __VA_ARGS__) 164 | #define READ_BYTES(...) CHECKED_READ(bytes, __VA_ARGS__) 165 | #define READ_BYTES_COPY(...) CHECKED_READ(bytes_copy, __VA_ARGS__) 166 | #define READ_INT_STRING(...) CHECKED_READ(int_string, __VA_ARGS__) 167 | #define READ_TLV(...) CHECKED_READ(tlv, __VA_ARGS__) 168 | 169 | /** @brief Read an unsigned char from a @code buffer. 170 | * 171 | * @param buf @code buffer to be read from 172 | * @param offset read at this offset in bytes 173 | * @param value read into this pointer, can be null if not wanted 174 | * @return the number of bytes read or a negative value if an error occured 175 | */ 176 | int read_u8(const struct buf *buf, int offset, uint8_t *value); 177 | 178 | /** @brief Read an unsigned short in little-endian byte order. 179 | * 180 | * @see read_u8 181 | */ 182 | int read_le16(const struct buf *buf, int offset, uint16_t *value); 183 | 184 | int read_be16(const struct buf *buf, int offset, uint16_t *value); 185 | 186 | int read_le32(const struct buf *buf, int offset, uint32_t *value); 187 | 188 | int read_be32(const struct buf *buf, int offset, uint32_t *value); 189 | 190 | int read_ether_addr(const struct buf *buf, int offset, struct ether_addr *addr); 191 | 192 | int read_bytes(const struct buf *buf, int offset, const uint8_t **bytes, int length); 193 | 194 | int read_bytes_copy(const struct buf *buf, int offset, uint8_t *bytes, int length); 195 | 196 | int read_int_string(const struct buf *buf, int offset, char *str, int length); 197 | 198 | /** @brief Get offset to next TLV 199 | * 200 | * Can also be used to check whether buffer points to a complete TLV. 201 | * 202 | * @param buf @code buffer to be read from 203 | * @param offset read at this offset in bytes 204 | * @param type pointer is set to the type of the TLV, can be null if not wanted 205 | * @param len pointer is set to the length of the TLV, can be null if not wanted 206 | * @param val pointer is set to the value of the TLV, can be null if not wanted 207 | * @return offset to next TLV or a negative value if an error occured 208 | */ 209 | int read_tlv(const struct buf *buf, int offset, uint8_t *type, uint16_t *len, const uint8_t **val); 210 | 211 | #endif /* OWL_WIRE_H */ 212 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(CMAKE_CXX_STANDARD 11) 2 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 3 | 4 | include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) 5 | 6 | add_executable(tests "") 7 | 8 | target_sources(tests PRIVATE 9 | test_wire.cpp 10 | test_awdl_sync.cpp 11 | test_awdl_peers.cpp 12 | test_awdl_election.cpp 13 | ) 14 | 15 | target_include_directories(tests PRIVATE ${CMAKE_SOURCE_DIR}/src) 16 | 17 | target_link_libraries(tests gtest gtest_main) 18 | target_link_libraries(tests awdl) 19 | -------------------------------------------------------------------------------- /tests/test_awdl_election.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | extern "C" { 21 | #include "election.h" 22 | #include "peers.h" 23 | } 24 | 25 | #include "gtest/gtest.h" 26 | 27 | #define TEST_ADDR(i) static const struct ether_addr TEST_ADDR##i = {{ i, i, i, i, i, i }} 28 | 29 | TEST_ADDR(0); 30 | TEST_ADDR(1); 31 | 32 | #define ASSERT_ETHEREQ(val1, val2) ASSERT_FALSE(compare_ether_addr(&val1, &val2)) 33 | #define ASSERT_ETHERNEQ(val1, val2) ASSERT_TRUE(compare_ether_addr(&val1, &val2)) 34 | 35 | void test_add_valid_peer(awdl_peers_t peers, const struct ether_addr *addr) { 36 | struct awdl_peer *peer; 37 | awdl_peer_add(peers, addr, 0, NULL, NULL); 38 | awdl_peer_get(peers, addr, &peer); 39 | peer->is_valid = true; 40 | } 41 | 42 | TEST(awdl_election, init) { 43 | struct awdl_election_state s; 44 | awdl_election_state_init(&s, &TEST_ADDR0); 45 | 46 | ASSERT_EQ(s.self_counter, 0); 47 | ASSERT_EQ(s.self_metric, 60); 48 | ASSERT_EQ(s.master_counter, 0); 49 | ASSERT_EQ(s.master_metric, 60); 50 | ASSERT_EQ(s.height, 0); 51 | ASSERT_ETHEREQ(s.self_addr, TEST_ADDR0); 52 | 53 | ASSERT_ETHEREQ(s.master_addr, TEST_ADDR0); 54 | ASSERT_ETHEREQ(s.sync_addr, TEST_ADDR0); 55 | ASSERT_ETHEREQ(s.self_addr, TEST_ADDR0); 56 | } 57 | 58 | TEST(awdl_election, elect_simple) { 59 | struct awdl_election_state s; 60 | struct awdl_peer_state p; 61 | awdl_election_state_init(&s, &TEST_ADDR0); 62 | awdl_peer_state_init(&p); 63 | 64 | test_add_valid_peer(p.peers, &TEST_ADDR1); 65 | 66 | awdl_election_run(&s, &p); 67 | 68 | ASSERT_ETHEREQ(s.master_addr, TEST_ADDR1); 69 | } 70 | 71 | TEST(awdl_election, elect_simple_invalid) { 72 | struct awdl_election_state s; 73 | struct awdl_peer_state p; 74 | awdl_election_state_init(&s, &TEST_ADDR0); 75 | awdl_peer_state_init(&p); 76 | 77 | awdl_peer_add(p.peers, &TEST_ADDR1, 0, NULL, NULL); 78 | 79 | awdl_election_run(&s, &p); 80 | 81 | ASSERT_ETHEREQ(s.master_addr, TEST_ADDR0); 82 | } 83 | 84 | TEST(awdl_election, counter_metric) { 85 | struct awdl_election_state s; 86 | struct awdl_peer_state p; 87 | struct awdl_peer *peer; 88 | awdl_election_state_init(&s, &TEST_ADDR0); 89 | awdl_peer_state_init(&p); 90 | 91 | test_add_valid_peer(p.peers, &TEST_ADDR1); 92 | awdl_peer_get(p.peers, &TEST_ADDR1, &peer); 93 | 94 | awdl_election_run(&s, &p); 95 | ASSERT_ETHEREQ(s.master_addr, TEST_ADDR1); 96 | 97 | peer->election.master_metric = 1000; 98 | awdl_election_run(&s, &p); 99 | ASSERT_ETHEREQ(s.master_addr, TEST_ADDR1); 100 | 101 | s.self_metric = 1000; 102 | awdl_election_run(&s, &p); 103 | ASSERT_ETHEREQ(s.master_addr, TEST_ADDR1); 104 | 105 | s.self_metric = 1001; 106 | awdl_election_run(&s, &p); 107 | ASSERT_ETHEREQ(s.master_addr, TEST_ADDR0); 108 | 109 | peer->election.master_counter = 1; 110 | awdl_election_run(&s, &p); 111 | ASSERT_ETHEREQ(s.master_addr, TEST_ADDR1); 112 | 113 | s.self_counter = 1; 114 | awdl_election_run(&s, &p); 115 | ASSERT_ETHEREQ(s.master_addr, TEST_ADDR0); 116 | } 117 | 118 | 119 | TEST(awdl_election, elect_cycle) { 120 | struct awdl_election_state s; 121 | struct awdl_peer_state p; 122 | struct awdl_peer *peer; 123 | awdl_election_state_init(&s, &TEST_ADDR0); 124 | awdl_peer_state_init(&p); 125 | 126 | test_add_valid_peer(p.peers, &TEST_ADDR1); 127 | awdl_peer_get(p.peers, &TEST_ADDR1, &peer); 128 | 129 | peer->election.master_metric = 1000; 130 | peer->election.self_metric = 1000; 131 | /* add top master */ 132 | peer->election.height = 1; 133 | peer->election.master_addr = TEST_ADDR0; 134 | 135 | awdl_election_run(&s, &p); 136 | 137 | ASSERT_ETHEREQ(s.master_addr, TEST_ADDR0); 138 | } 139 | -------------------------------------------------------------------------------- /tests/test_awdl_peers.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | extern "C" { 21 | #include "peers.h" 22 | } 23 | 24 | #include "gtest/gtest.h" 25 | 26 | #define TEST_ADDR(i) static const struct ether_addr TEST_ADDR##i = {{ i, i, i, i, i, i }} 27 | 28 | TEST_ADDR(0); 29 | TEST_ADDR(1); 30 | 31 | TEST(awdl_peers, init_free) { 32 | awdl_peers_t p = awdl_peers_init(); 33 | EXPECT_TRUE(p); 34 | EXPECT_EQ(awdl_peers_length(p), 0); 35 | awdl_peers_free(p); 36 | } 37 | 38 | TEST(awdl_peers, add) { 39 | int s; 40 | awdl_peers_t p = awdl_peers_init(); 41 | s = awdl_peer_add(p, &TEST_ADDR0, 0, NULL, NULL); 42 | EXPECT_EQ(s, PEERS_OK); 43 | EXPECT_EQ(awdl_peers_length(p), 1); 44 | awdl_peers_free(p); 45 | } 46 | 47 | TEST(awdl_peers, add_two) { 48 | int s; 49 | awdl_peers_t p = awdl_peers_init(); 50 | s = awdl_peer_add(p, &TEST_ADDR0, 0, NULL, NULL); 51 | EXPECT_EQ(s, PEERS_OK); 52 | EXPECT_EQ(awdl_peers_length(p), 1); 53 | s = awdl_peer_add(p, &TEST_ADDR1, 0, NULL, NULL); 54 | EXPECT_EQ(s, PEERS_OK); 55 | EXPECT_EQ(awdl_peers_length(p), 2); 56 | awdl_peers_free(p); 57 | } 58 | 59 | TEST(awdl_peers, add_same) { 60 | int s; 61 | awdl_peers_t p = awdl_peers_init(); 62 | s = awdl_peer_add(p, &TEST_ADDR0, 0, NULL, NULL); 63 | EXPECT_EQ(s, PEERS_OK); 64 | EXPECT_EQ(awdl_peers_length(p), 1); 65 | s = awdl_peer_add(p, &TEST_ADDR0, 0, NULL, NULL); 66 | EXPECT_EQ(s, PEERS_UPDATE); 67 | EXPECT_EQ(awdl_peers_length(p), 1); 68 | awdl_peers_free(p); 69 | } 70 | 71 | TEST(awdl_peers, remove) { 72 | int s; 73 | awdl_peers_t p = awdl_peers_init(); 74 | awdl_peer_add(p, &TEST_ADDR0, 0, NULL, NULL); 75 | s = awdl_peer_remove(p, &TEST_ADDR0, NULL, NULL); 76 | EXPECT_EQ(s, PEERS_OK); 77 | EXPECT_EQ(awdl_peers_length(p), 0); 78 | awdl_peers_free(p); 79 | } 80 | 81 | TEST(awdl_peers, remove_empty) { 82 | int s; 83 | awdl_peers_t p = awdl_peers_init(); 84 | s = awdl_peer_remove(p, &TEST_ADDR0, NULL, NULL); 85 | EXPECT_EQ(s, PEERS_MISSING); 86 | EXPECT_EQ(awdl_peers_length(p), 0); 87 | awdl_peers_free(p); 88 | } 89 | 90 | TEST(awdl_peers, remove_twice) { 91 | int s; 92 | awdl_peers_t p = awdl_peers_init(); 93 | awdl_peer_add(p, &TEST_ADDR0, 0, NULL, NULL); 94 | awdl_peer_remove(p, &TEST_ADDR0, NULL, NULL); 95 | s = awdl_peer_remove(p, &TEST_ADDR0, NULL, NULL); 96 | EXPECT_EQ(s, PEERS_MISSING); 97 | EXPECT_EQ(awdl_peers_length(p), 0); 98 | awdl_peers_free(p); 99 | } 100 | 101 | static int count_cb = 0; 102 | 103 | static void test_cb(struct awdl_peer *p, void *ignore) { 104 | (void) ignore; 105 | count_cb++; 106 | EXPECT_TRUE(!memcmp(&TEST_ADDR0, &p->addr, sizeof(struct ether_addr))); 107 | } 108 | 109 | TEST(awdl_peers, remove_timedout) { 110 | struct awdl_peer *peer = NULL; 111 | uint64_t now = 0; 112 | awdl_peers_t p = awdl_peers_init(); 113 | awdl_peer_add(p, &TEST_ADDR0, now, NULL, NULL); 114 | awdl_peer_get(p, &TEST_ADDR0, &peer); 115 | peer->is_valid = 1; 116 | EXPECT_EQ(awdl_peers_length(p), 1); 117 | awdl_peers_remove(p, now, test_cb, NULL); 118 | EXPECT_EQ(awdl_peers_length(p), 1); 119 | EXPECT_EQ(count_cb, 0); 120 | now++; 121 | awdl_peers_remove(p, now, test_cb, NULL); 122 | EXPECT_EQ(awdl_peers_length(p), 0); 123 | EXPECT_EQ(count_cb, 1); 124 | awdl_peers_free(p); 125 | } 126 | 127 | TEST(awdl_peers, print) { 128 | char buf[1000]; // Buffer is large enough 129 | awdl_peers_t p = awdl_peers_init(); 130 | awdl_peer_add(p, &TEST_ADDR0, 0, NULL, NULL); 131 | awdl_peer_add(p, &TEST_ADDR1, 0, NULL, NULL); 132 | int len = awdl_peers_print(p, buf, sizeof(buf)); 133 | EXPECT_EQ(len, strlen(buf)); 134 | EXPECT_STREQ(buf, ": 0:0:0:0:0:0 (met 60, ctr 0)\n" 135 | ": 1:1:1:1:1:1 (met 60, ctr 0)\n"); 136 | } 137 | 138 | TEST(awdl_peers, print_overflow) { 139 | char buf[30]; // Buffer is too small 140 | awdl_peers_t p = awdl_peers_init(); 141 | awdl_peer_add(p, &TEST_ADDR0, 0, NULL, NULL); 142 | awdl_peer_add(p, &TEST_ADDR1, 0, NULL, NULL); 143 | int len = awdl_peers_print(p, buf, sizeof(buf)); 144 | EXPECT_GT(len, strlen(buf)); // would have written more 145 | EXPECT_EQ(strlen(buf), sizeof(buf) - 1); // buffer is full 146 | EXPECT_STREQ(buf, ": 0:0:0:0:0:0 (met 6"); 147 | } 148 | -------------------------------------------------------------------------------- /tests/test_awdl_sync.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | extern "C" { 21 | #include "sync.h" 22 | #include "ieee80211.h" 23 | } 24 | 25 | #include "gtest/gtest.h" 26 | 27 | static struct awdl_sync_state *test_state(uint64_t now) { 28 | static struct awdl_sync_state state; 29 | awdl_sync_state_init(&state, now); 30 | return &state; 31 | } 32 | 33 | TEST(awdl_sync, next_aw_tu) { 34 | uint64_t now = 0; 35 | struct awdl_sync_state *state = test_state(now); 36 | uint64_t eaw_period = 64; 37 | 38 | for (uint64_t tu = 0; tu < 4 * eaw_period; tu++) { 39 | for (; now < ieee80211_tu_to_usec(tu + 1); now++) { 40 | uint16_t next_aw_tu = awdl_sync_next_aw_tu(now, state); 41 | EXPECT_EQ(next_aw_tu, eaw_period - (tu % eaw_period)); 42 | } 43 | } 44 | } 45 | 46 | TEST(awdl_sync, current_aw) { 47 | uint64_t now = 0; 48 | struct awdl_sync_state *state; 49 | uint16_t aw, current_aw; 50 | 51 | aw = 0; 52 | state = test_state(now); 53 | state->aw_counter = aw; 54 | current_aw = awdl_sync_current_aw(now, state); 55 | EXPECT_EQ(current_aw, aw); 56 | 57 | aw = 1337; 58 | state = test_state(now); 59 | state->aw_counter = aw; 60 | current_aw = awdl_sync_current_aw(now, state); 61 | EXPECT_EQ(current_aw, aw); 62 | 63 | aw = 0xffff; 64 | state = test_state(now); 65 | state->aw_counter = aw; 66 | current_aw = awdl_sync_current_aw(now, state); 67 | EXPECT_EQ(current_aw, aw); 68 | } 69 | 70 | TEST(awdl_sync, current_aw_timedelta) { 71 | uint64_t now = 0; 72 | struct awdl_sync_state *state = test_state(now); 73 | uint64_t tu = 0; 74 | 75 | for (uint16_t aw = 0; aw < 0xffff; aw++) { 76 | for (; tu < (aw + 1u) * state->aw_period; tu++) { 77 | uint16_t current_aw = awdl_sync_current_aw(ieee80211_tu_to_usec(tu), state); 78 | EXPECT_EQ(current_aw, aw); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /tests/test_wire.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * OWL: an open Apple Wireless Direct Link (AWDL) implementation 3 | * Copyright (C) 2018 The Open Wireless Link Project (https://owlink.org) 4 | * Copyright (C) 2018 Milan Stute 5 | * 6 | * This program is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation, either version 3 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program. If not, see . 18 | */ 19 | 20 | extern "C" { 21 | #include "state.h" 22 | #include "wire.h" 23 | #include "tx.h" 24 | #include "channel.h" 25 | } 26 | 27 | #include "gtest/gtest.h" 28 | 29 | static struct buf *create_test_buf(int len) { 30 | return buf_new_owned(len); 31 | } 32 | 33 | static void destroy_test_buf(struct buf *buf) { 34 | buf_free(buf); 35 | } 36 | 37 | TEST(wire, buf_take) { 38 | bool success = 0; 39 | struct buf *frame = create_test_buf(2); 40 | 41 | write_u8(frame, 0, 4); 42 | write_u8(frame, 1, 2); 43 | 44 | BUF_TAKE(frame, 1); 45 | 46 | uint8_t x; 47 | read_u8(frame, 0, &x); 48 | EXPECT_EQ(x, 4); 49 | 50 | success = 1; 51 | 52 | wire_error: 53 | EXPECT_TRUE(success); 54 | EXPECT_EQ(buf_len(frame), 1); 55 | destroy_test_buf(frame); 56 | } 57 | 58 | TEST(wire, buf_take_oob) { 59 | bool success = 0; 60 | struct buf *frame = create_test_buf(1); 61 | 62 | BUF_TAKE(frame, buf_len(frame) + 1); 63 | success = 1; 64 | 65 | wire_error: 66 | EXPECT_FALSE(success); 67 | EXPECT_EQ(buf_len(frame), 1); 68 | destroy_test_buf(frame); 69 | } 70 | 71 | 72 | TEST(wire, buf_take_negative) { 73 | bool success = 0; 74 | struct buf *frame = create_test_buf(1); 75 | 76 | BUF_TAKE(frame, -1); 77 | success = 1; 78 | 79 | wire_error: 80 | EXPECT_FALSE(success); 81 | EXPECT_EQ(buf_len(frame), 1); 82 | destroy_test_buf(frame); 83 | } 84 | 85 | TEST(wire, buf_strip) { 86 | bool success = 0; 87 | struct buf *frame = create_test_buf(2); 88 | 89 | write_u8(frame, 0, 4); 90 | write_u8(frame, 1, 2); 91 | 92 | BUF_STRIP(frame, 1); 93 | 94 | uint8_t x; 95 | read_u8(frame, 0, &x); 96 | EXPECT_EQ(x, 2); 97 | 98 | success = 1; 99 | 100 | wire_error: 101 | EXPECT_TRUE(success); 102 | EXPECT_EQ(buf_len(frame), 1); 103 | destroy_test_buf(frame); 104 | } 105 | 106 | TEST(wire, buf_strip_oob) { 107 | bool success = 0; 108 | struct buf *frame = create_test_buf(1); 109 | 110 | BUF_STRIP(frame, buf_len(frame) + 1); 111 | success = 1; 112 | 113 | wire_error: 114 | EXPECT_FALSE(success); 115 | EXPECT_EQ(buf_len(frame), 1); 116 | destroy_test_buf(frame); 117 | } 118 | 119 | 120 | TEST(wire, buf_strip_negative) { 121 | bool success = 0; 122 | struct buf *frame = create_test_buf(1); 123 | 124 | BUF_STRIP(frame, -1); 125 | success = 1; 126 | 127 | wire_error: 128 | EXPECT_FALSE(success); 129 | EXPECT_EQ(buf_len(frame), 1); 130 | destroy_test_buf(frame); 131 | } 132 | 133 | TEST(wire, read_tlv) { 134 | struct ether_addr addr; 135 | struct awdl_state state; 136 | struct buf *frame; 137 | uint8_t *ptr, *start; 138 | int tlv_len; 139 | 140 | awdl_init_state(&state, "", &addr, CHAN_OPCLASS_6, 0); 141 | 142 | frame = create_test_buf(1024); 143 | // TODO use wire API in awdl_init_ functions, so cast is not necessary 144 | ptr = (uint8_t *) buf_data(frame); 145 | start = ptr; 146 | 147 | ptr += awdl_init_sync_params_tlv(ptr, &state); 148 | ptr += awdl_init_election_params_tlv(ptr, &state); 149 | ptr += awdl_init_chanseq_tlv(ptr, &state); 150 | ptr += awdl_init_service_params_tlv(ptr, &state); 151 | ptr += awdl_init_arpa_tlv(ptr, &state); 152 | ptr += awdl_init_data_path_state_tlv(ptr, &state); 153 | ptr += awdl_init_version_tlv(ptr, &state); 154 | 155 | buf_take(frame, buf_len(frame) - (ptr - start)); 156 | 157 | uint8_t type; 158 | while ((tlv_len = read_tlv(frame, 0, &type, NULL, NULL)) > 0) { 159 | EXPECT_STRNE(awdl_tlv_as_str(type), "Unknown"); 160 | buf_strip(frame, tlv_len); 161 | } 162 | 163 | EXPECT_EQ(buf_len(frame), 0); 164 | 165 | buf_free(frame); 166 | } 167 | 168 | TEST(wire, read_u8) { 169 | struct buf *frame = create_test_buf(1); 170 | 171 | EXPECT_LT(read_u8(frame, -1, NULL), 0); 172 | EXPECT_EQ(read_u8(frame, 0, NULL), 1); 173 | EXPECT_LT(read_u8(frame, 1, NULL), 0); 174 | 175 | destroy_test_buf(frame); 176 | } 177 | 178 | TEST(wire, checked_read_u8) { 179 | struct buf *frame = create_test_buf(1); 180 | 181 | int expect_fail = 0; 182 | READ_U8(frame, 0, NULL); 183 | EXPECT_FALSE(expect_fail); 184 | 185 | expect_fail = 1; 186 | READ_U8(frame, 1, NULL); 187 | EXPECT_FALSE(expect_fail); // we should not be here 188 | 189 | wire_error: 190 | EXPECT_TRUE(expect_fail); 191 | destroy_test_buf(frame); 192 | } 193 | 194 | TEST(wire, read_le16) { 195 | struct buf *frame = create_test_buf(2); 196 | 197 | EXPECT_LT(read_le16(frame, -1, NULL), 0); 198 | EXPECT_EQ(read_le16(frame, 0, NULL), 2); 199 | EXPECT_LT(read_le16(frame, 1, NULL), 0); 200 | 201 | destroy_test_buf(frame); 202 | } 203 | 204 | TEST(wire, checked_read_le16) { 205 | struct buf *frame = create_test_buf(2); 206 | 207 | int expect_fail = 0; 208 | READ_LE16(frame, 0, NULL); 209 | EXPECT_FALSE(expect_fail); 210 | 211 | expect_fail = 1; 212 | READ_LE16(frame, 1, NULL); 213 | EXPECT_FALSE(expect_fail); // we should not be here 214 | 215 | wire_error: 216 | EXPECT_TRUE(expect_fail); 217 | destroy_test_buf(frame); 218 | } 219 | 220 | TEST(wire, read_be16) { 221 | struct buf *frame = create_test_buf(2); 222 | 223 | EXPECT_LT(read_be16(frame, -1, NULL), 0); 224 | EXPECT_EQ(read_be16(frame, 0, NULL), 2); 225 | EXPECT_LT(read_be16(frame, 1, NULL), 0); 226 | 227 | destroy_test_buf(frame); 228 | } 229 | 230 | TEST(wire, checked_read_be16) { 231 | struct buf *frame = create_test_buf(2); 232 | 233 | int expect_fail = 0; 234 | READ_BE16(frame, 0, NULL); 235 | EXPECT_FALSE(expect_fail); 236 | 237 | expect_fail = 1; 238 | READ_BE16(frame, 1, NULL); 239 | EXPECT_FALSE(expect_fail); // we should not be here 240 | 241 | wire_error: 242 | EXPECT_TRUE(expect_fail); 243 | destroy_test_buf(frame); 244 | } 245 | 246 | TEST(wire, read_le32) { 247 | struct buf *frame = create_test_buf(4); 248 | 249 | EXPECT_LT(read_le32(frame, -1, NULL), 0); 250 | EXPECT_EQ(read_le32(frame, 0, NULL), 4); 251 | EXPECT_LT(read_le32(frame, 1, NULL), 0); 252 | 253 | destroy_test_buf(frame); 254 | } 255 | 256 | TEST(wire, checked_read_le32) { 257 | struct buf *frame = create_test_buf(4); 258 | 259 | int expect_fail = 0; 260 | READ_LE32(frame, 0, NULL); 261 | EXPECT_FALSE(expect_fail); 262 | 263 | expect_fail = 1; 264 | READ_LE32(frame, 1, NULL); 265 | EXPECT_FALSE(expect_fail); // we should not be here 266 | 267 | wire_error: 268 | EXPECT_TRUE(expect_fail); 269 | destroy_test_buf(frame); 270 | } 271 | 272 | 273 | TEST(wire, read_be32) { 274 | struct buf *frame = create_test_buf(4); 275 | 276 | EXPECT_LT(read_be32(frame, -1, NULL), 0); 277 | EXPECT_EQ(read_be32(frame, 0, NULL), 4); 278 | EXPECT_LT(read_be32(frame, 1, NULL), 0); 279 | 280 | destroy_test_buf(frame); 281 | } 282 | 283 | TEST(wire, checked_read_be32) { 284 | struct buf *frame = create_test_buf(4); 285 | 286 | int expect_fail = 0; 287 | READ_BE32(frame, 0, NULL); 288 | EXPECT_FALSE(expect_fail); 289 | 290 | expect_fail = 1; 291 | READ_BE32(frame, 1, NULL); 292 | EXPECT_FALSE(expect_fail); // we should not be here 293 | 294 | wire_error: 295 | EXPECT_TRUE(expect_fail); 296 | destroy_test_buf(frame); 297 | } 298 | 299 | TEST(wire, read_ether_addr) { 300 | struct buf *frame = create_test_buf(6); 301 | 302 | EXPECT_LT(read_ether_addr(frame, -1, NULL), 0); 303 | EXPECT_EQ(read_ether_addr(frame, 0, NULL), 6); 304 | EXPECT_LT(read_ether_addr(frame, 1, NULL), 0); 305 | 306 | destroy_test_buf(frame); 307 | } 308 | 309 | TEST(wire, checked_read_ether_addr) { 310 | struct buf *frame = create_test_buf(6); 311 | 312 | int expect_fail = 0; 313 | READ_ETHER_ADDR(frame, 0, NULL); 314 | EXPECT_FALSE(expect_fail); 315 | 316 | expect_fail = 1; 317 | READ_ETHER_ADDR(frame, 1, NULL); 318 | EXPECT_FALSE(expect_fail); // we should not be here 319 | 320 | wire_error: 321 | EXPECT_TRUE(expect_fail); 322 | destroy_test_buf(frame); 323 | } 324 | 325 | TEST(wire, read_bytes) { 326 | const static int LEN = 100; 327 | struct buf *frame = create_test_buf(LEN); 328 | 329 | EXPECT_LT(read_bytes(frame, -1, NULL, LEN), 0); 330 | EXPECT_EQ(read_bytes(frame, 0, NULL, LEN), LEN); 331 | EXPECT_LT(read_bytes(frame, 1, NULL, LEN), 0); 332 | 333 | destroy_test_buf(frame); 334 | } 335 | 336 | TEST(wire, checked_read_bytes) { 337 | const static int LEN = 100; 338 | struct buf *frame = create_test_buf(LEN); 339 | 340 | int expect_fail = 0; 341 | READ_BYTES(frame, 0, NULL, LEN); 342 | EXPECT_FALSE(expect_fail); 343 | 344 | expect_fail = 1; 345 | READ_BYTES(frame, 1, NULL, LEN); 346 | EXPECT_FALSE(expect_fail); // we should not be here 347 | 348 | wire_error: 349 | EXPECT_TRUE(expect_fail); 350 | destroy_test_buf(frame); 351 | } 352 | 353 | TEST(wire, read_int_string) { 354 | char name[] = "owl"; 355 | char read[4]; 356 | struct buf *frame = create_test_buf(1 + strlen(name)); 357 | 358 | write_u8(frame, 0, strlen(name)); 359 | write_bytes(frame, 1, (uint8_t *) name, strlen(name)); 360 | 361 | EXPECT_EQ(read_int_string(frame, 0, read, 0), 1); 362 | EXPECT_STREQ(read, ""); 363 | EXPECT_EQ(read_int_string(frame, 0, read, 1), 2); 364 | EXPECT_STREQ(read, "o"); 365 | EXPECT_EQ(read_int_string(frame, 0, read, 2), 3); 366 | EXPECT_STREQ(read, "ow"); 367 | EXPECT_EQ(read_int_string(frame, 0, read, 3), 4); 368 | EXPECT_STREQ(read, "owl"); 369 | EXPECT_EQ(read_int_string(frame, 0, read, sizeof(read)), 4); 370 | EXPECT_STREQ(read, name); 371 | 372 | destroy_test_buf(frame); 373 | } 374 | 375 | TEST(wire, checked_read_int_string) { 376 | char name[] = "owl"; 377 | char read[4]; 378 | struct buf *frame = create_test_buf(1 + strlen(name)); 379 | 380 | write_u8(frame, 0, strlen(name)); 381 | write_bytes(frame, 1, (uint8_t *) name, strlen(name)); 382 | 383 | int expect_fail = 0; 384 | READ_INT_STRING(frame, 0, NULL, sizeof(read)); 385 | EXPECT_FALSE(expect_fail); 386 | 387 | expect_fail = 1; 388 | READ_INT_STRING(frame, buf_len(frame), NULL, sizeof(read)); 389 | EXPECT_FALSE(expect_fail); // we should not be here 390 | 391 | wire_error: 392 | EXPECT_TRUE(expect_fail); 393 | destroy_test_buf(frame); 394 | } 395 | 396 | TEST(wire, write_read_u8) { 397 | struct buf *frame = create_test_buf(1); 398 | uint8_t write = 42; 399 | uint8_t read = 0; 400 | 401 | EXPECT_EQ(write_u8((struct buf *)frame, 0, write), 1); 402 | EXPECT_EQ(read_u8(frame, 0, &read), 1); 403 | EXPECT_EQ(read, write); 404 | 405 | destroy_test_buf(frame); 406 | } 407 | 408 | TEST(wire, write_read_le16) { 409 | struct buf *frame = create_test_buf(2); 410 | uint16_t write = 42; 411 | uint16_t read = 0; 412 | 413 | EXPECT_EQ(write_le16((struct buf *)frame, 0, write), 2); 414 | EXPECT_EQ(read_le16(frame, 0, &read), 2); 415 | EXPECT_EQ(read, write); 416 | 417 | destroy_test_buf(frame); 418 | } 419 | 420 | TEST(wire, write_read_be16) { 421 | struct buf *frame = create_test_buf(2); 422 | uint16_t write = 42; 423 | uint16_t read = 0; 424 | 425 | EXPECT_EQ(write_be16((struct buf *)frame, 0, write), 2); 426 | EXPECT_EQ(read_be16(frame, 0, &read), 2); 427 | EXPECT_EQ(read, write); 428 | 429 | destroy_test_buf(frame); 430 | } 431 | 432 | TEST(wire, write_le16_read_be16) { 433 | struct buf *frame = create_test_buf(2); 434 | uint16_t write = 42; 435 | uint16_t read = 0; 436 | 437 | EXPECT_EQ(write_le16((struct buf *)frame, 0, write), 2); 438 | EXPECT_EQ(read_be16(frame, 0, &read), 2); 439 | EXPECT_NE(read, write); 440 | 441 | destroy_test_buf(frame); 442 | } 443 | 444 | TEST(wire, write_be16_read_le16) { 445 | struct buf *frame = create_test_buf(2); 446 | uint16_t write = 42; 447 | uint16_t read = 0; 448 | 449 | EXPECT_EQ(write_be16((struct buf *)frame, 0, write), 2); 450 | EXPECT_EQ(read_le16(frame, 0, &read), 2); 451 | EXPECT_NE(read, write); 452 | 453 | destroy_test_buf(frame); 454 | } 455 | 456 | TEST(wire, write_read_le32) { 457 | struct buf *frame = create_test_buf(4); 458 | uint32_t write = 42; 459 | uint32_t read = 0; 460 | 461 | EXPECT_EQ(write_le32((struct buf *)frame, 0, write), 4); 462 | EXPECT_EQ(read_le32(frame, 0, &read), 4); 463 | EXPECT_EQ(read, write); 464 | 465 | destroy_test_buf(frame); 466 | } 467 | 468 | TEST(wire, write_read_be32) { 469 | struct buf *frame = create_test_buf(4); 470 | uint32_t write = 42; 471 | uint32_t read = 0; 472 | 473 | EXPECT_EQ(write_be32((struct buf *)frame, 0, write), 4); 474 | EXPECT_EQ(read_be32(frame, 0, &read), 4); 475 | EXPECT_EQ(read, write); 476 | 477 | destroy_test_buf(frame); 478 | } 479 | 480 | TEST(wire, write_le32_read_be32) { 481 | struct buf *frame = create_test_buf(4); 482 | uint32_t write = 42; 483 | uint32_t read = 0; 484 | 485 | EXPECT_EQ(write_le32((struct buf *)frame, 0, write), 4); 486 | EXPECT_EQ(read_be32(frame, 0, &read), 4); 487 | EXPECT_NE(read, write); 488 | 489 | destroy_test_buf(frame); 490 | } 491 | 492 | TEST(wire, write_be32_read_le32) { 493 | struct buf *frame = create_test_buf(4); 494 | uint32_t write = 42; 495 | uint32_t read = 0; 496 | 497 | EXPECT_EQ(write_be32((struct buf *)frame, 0, write), 4); 498 | EXPECT_EQ(read_le32(frame, 0, &read), 4); 499 | EXPECT_NE(read, write); 500 | 501 | destroy_test_buf(frame); 502 | } 503 | 504 | TEST(wire, write_read_ether_addr) { 505 | struct buf *frame = create_test_buf(6); 506 | struct ether_addr write = {{ 0x01, 0x02, 0x03, 0x04, 0x05 }}; 507 | struct ether_addr read = {{ 0x00, 0x00, 0x00, 0x00, 0x00 }}; 508 | 509 | EXPECT_EQ(write_ether_addr((struct buf *)frame, 0, &write), 6); 510 | EXPECT_EQ(read_ether_addr(frame, 0, &read), 6); 511 | for (int i = 0; i < 6; i++) 512 | EXPECT_EQ(read.ether_addr_octet[i], write.ether_addr_octet[i]); 513 | 514 | destroy_test_buf(frame); 515 | } 516 | 517 | TEST(wire, write_read_bytes) { 518 | const static uint8_t LEN = 100; 519 | 520 | struct buf *frame = create_test_buf(LEN); 521 | uint8_t write[LEN]; 522 | const uint8_t *read; 523 | 524 | for (uint8_t i = 0; i < LEN; i++) 525 | write[i] = i; 526 | 527 | EXPECT_EQ(write_bytes((struct buf *)frame, 0, write, LEN), LEN); 528 | EXPECT_EQ(read_bytes(frame, 0, &read, LEN), LEN); 529 | for (int i = 0; i < LEN; i++) 530 | EXPECT_EQ(read[i], write[i]); 531 | 532 | destroy_test_buf(frame); 533 | } 534 | --------------------------------------------------------------------------------