From ae6c98a48da409d040604aeffb84a38155fb5bac Mon Sep 17 00:00:00 2001 From: Marc Date: Tue, 30 Nov 2021 22:39:26 +0000 Subject: Initial Commit Signed-off-by: Marc --- .clang-format | 8 + .github/workflows/x86_64.yml | 27 + .gitignore | 23 + AUTHORS | 10 + CMakeLists.txt | 51 ++ COPYING | 15 + LICENSE | 201 +++++ README.md | 88 ++ benchmark/Makefile | 9 + benchmark/benchmark_beacon.c | 37 + examples/generate_beacon/README.md | 19 + examples/generate_beacon/generate_beacon.c | 80 ++ examples/generate_rtscts/README.md | 23 + examples/generate_rtscts/generate_rtscts.c | 78 ++ examples/parse_beacon/README.md | 65 ++ examples/parse_beacon/parse_beacon.c | 158 ++++ examples/parse_eapol/README.md | 74 ++ examples/parse_eapol/parse_eapol.c | 140 ++++ scripts/generate_entry_header.sh | 31 + src/libwifi.h | 75 ++ src/libwifi/core/core.c | 46 + src/libwifi/core/core.h | 53 ++ src/libwifi/core/frame/control/cts.h | 35 + src/libwifi/core/frame/control/rts.h | 38 + src/libwifi/core/frame/crc.c | 63 ++ src/libwifi/core/frame/crc.h | 49 ++ src/libwifi/core/frame/data/data.h | 32 + src/libwifi/core/frame/frame.c | 145 ++++ src/libwifi/core/frame/frame.h | 334 ++++++++ src/libwifi/core/frame/management/action.h | 93 +++ src/libwifi/core/frame/management/assoc_request.h | 51 ++ src/libwifi/core/frame/management/assoc_response.h | 54 ++ src/libwifi/core/frame/management/atim.h | 33 + src/libwifi/core/frame/management/authentication.h | 54 ++ src/libwifi/core/frame/management/beacon.h | 54 ++ src/libwifi/core/frame/management/common.h | 101 +++ .../core/frame/management/deauthentication.h | 55 ++ src/libwifi/core/frame/management/disassociation.h | 55 ++ src/libwifi/core/frame/management/probe_request.h | 38 + src/libwifi/core/frame/management/probe_response.h | 54 ++ .../core/frame/management/reassoc_request.h | 54 ++ .../core/frame/management/reassoc_response.h | 54 ++ src/libwifi/core/frame/management/timing_ad.h | 82 ++ src/libwifi/core/frame/tag.c | 131 +++ src/libwifi/core/frame/tag.h | 306 +++++++ src/libwifi/core/frame/tag_iterator.c | 55 ++ src/libwifi/core/frame/tag_iterator.h | 53 ++ src/libwifi/core/misc/byteswap.h | 31 + src/libwifi/core/misc/epoch.c | 23 + src/libwifi/core/misc/epoch.h | 26 + src/libwifi/core/misc/llc.h | 33 + src/libwifi/core/misc/radiotap.h | 83 ++ src/libwifi/core/misc/security.h | 289 +++++++ src/libwifi/core/misc/types.h | 218 +++++ src/libwifi/core/radiotap/COPYING | 14 + src/libwifi/core/radiotap/platform.h | 81 ++ src/libwifi/core/radiotap/radiotap.c | 469 +++++++++++ src/libwifi/core/radiotap/radiotap.h | 221 +++++ src/libwifi/core/radiotap/radiotap_iter.h | 101 +++ src/libwifi/gen/control/cts.c | 30 + src/libwifi/gen/control/cts.h | 30 + src/libwifi/gen/control/rts.c | 32 + src/libwifi/gen/control/rts.h | 32 + src/libwifi/gen/management/action.c | 110 +++ src/libwifi/gen/management/action.h | 80 ++ src/libwifi/gen/management/assoc_request.c | 85 ++ src/libwifi/gen/management/assoc_request.h | 39 + src/libwifi/gen/management/assoc_response.c | 106 +++ src/libwifi/gen/management/assoc_response.h | 69 ++ src/libwifi/gen/management/atim.c | 35 + src/libwifi/gen/management/atim.h | 24 + src/libwifi/gen/management/authentication.c | 81 ++ src/libwifi/gen/management/authentication.h | 64 ++ src/libwifi/gen/management/beacon.c | 117 +++ src/libwifi/gen/management/beacon.h | 78 ++ src/libwifi/gen/management/common.h | 54 ++ src/libwifi/gen/management/deauthentication.c | 82 ++ src/libwifi/gen/management/deauthentication.h | 63 ++ src/libwifi/gen/management/disassociation.c | 80 ++ src/libwifi/gen/management/disassociation.h | 63 ++ src/libwifi/gen/management/probe_request.c | 76 ++ src/libwifi/gen/management/probe_request.h | 64 ++ src/libwifi/gen/management/probe_response.c | 118 +++ src/libwifi/gen/management/probe_response.h | 78 ++ src/libwifi/gen/management/reassoc_request.c | 87 ++ src/libwifi/gen/management/reassoc_request.h | 30 + src/libwifi/gen/management/reassoc_response.c | 108 +++ src/libwifi/gen/management/reassoc_response.h | 70 ++ src/libwifi/gen/management/timing_ad.c | 111 +++ src/libwifi/gen/management/timing_ad.h | 32 + src/libwifi/gen/misc/radiotap.c | 123 +++ src/libwifi/gen/misc/radiotap.h | 31 + src/libwifi/parse/data/data.c | 48 ++ src/libwifi/parse/data/data.h | 26 + src/libwifi/parse/data/eapol.c | 190 +++++ src/libwifi/parse/data/eapol.h | 91 ++ src/libwifi/parse/management/assoc_request.c | 79 ++ src/libwifi/parse/management/assoc_request.h | 32 + src/libwifi/parse/management/assoc_response.c | 92 ++ src/libwifi/parse/management/assoc_response.h | 35 + src/libwifi/parse/management/beacon.c | 91 ++ src/libwifi/parse/management/beacon.h | 35 + src/libwifi/parse/management/common.c | 192 +++++ src/libwifi/parse/management/common.h | 70 ++ src/libwifi/parse/management/deauthentication.c | 74 ++ src/libwifi/parse/management/deauthentication.h | 25 + src/libwifi/parse/management/disassociation.c | 72 ++ src/libwifi/parse/management/disassociation.h | 25 + src/libwifi/parse/management/probe_request.c | 72 ++ src/libwifi/parse/management/probe_request.h | 32 + src/libwifi/parse/management/probe_response.c | 88 ++ src/libwifi/parse/management/probe_response.h | 35 + src/libwifi/parse/management/reassoc_request.c | 79 ++ src/libwifi/parse/management/reassoc_request.h | 32 + src/libwifi/parse/management/reassoc_response.c | 92 ++ src/libwifi/parse/management/reassoc_response.h | 35 + src/libwifi/parse/misc/radiotap.c | 126 +++ src/libwifi/parse/misc/radiotap.h | 39 + src/libwifi/parse/misc/security.c | 685 +++++++++++++++ src/libwifi/parse/misc/security.h | 124 +++ test/CMakeLists.txt | 16 + test/pcaps/assoc_req.pcap | Bin 0 -> 4374 bytes test/pcaps/assoc_resp.pcap | Bin 0 -> 3924 bytes test/pcaps/auth.pcap | Bin 0 -> 6524 bytes test/pcaps/beacons_with_221.pcap | Bin 0 -> 7674 bytes test/pcaps/deauth.pcap | Bin 0 -> 3074 bytes test/pcaps/deauth_with_221.pcap | Bin 0 -> 5024 bytes test/pcaps/disassoc.pcap | Bin 0 -> 3074 bytes test/pcaps/probe_req.pcap | Bin 0 -> 4074 bytes test/pcaps/probe_resp_with_221.pcap | Bin 0 -> 7874 bytes test/pcaps/reassoc_req.pcap | Bin 0 -> 4674 bytes test/pcaps/reassoc_resp.pcap | Bin 0 -> 3924 bytes test/src/.clang-format | 8 + test/src/helpers.c | 31 + test/src/helpers.h | 60 ++ test/src/test_generation.c | 924 +++++++++++++++++++++ test/src/test_misc.c | 30 + test/src/test_parsing.c | 613 ++++++++++++++ 138 files changed, 11553 insertions(+) create mode 100644 .clang-format create mode 100644 .github/workflows/x86_64.yml create mode 100644 .gitignore create mode 100644 AUTHORS create mode 100644 CMakeLists.txt create mode 100644 COPYING create mode 100644 LICENSE create mode 100644 README.md create mode 100644 benchmark/Makefile create mode 100644 benchmark/benchmark_beacon.c create mode 100644 examples/generate_beacon/README.md create mode 100644 examples/generate_beacon/generate_beacon.c create mode 100644 examples/generate_rtscts/README.md create mode 100644 examples/generate_rtscts/generate_rtscts.c create mode 100644 examples/parse_beacon/README.md create mode 100644 examples/parse_beacon/parse_beacon.c create mode 100644 examples/parse_eapol/README.md create mode 100644 examples/parse_eapol/parse_eapol.c create mode 100755 scripts/generate_entry_header.sh create mode 100644 src/libwifi.h create mode 100644 src/libwifi/core/core.c create mode 100644 src/libwifi/core/core.h create mode 100644 src/libwifi/core/frame/control/cts.h create mode 100644 src/libwifi/core/frame/control/rts.h create mode 100644 src/libwifi/core/frame/crc.c create mode 100644 src/libwifi/core/frame/crc.h create mode 100644 src/libwifi/core/frame/data/data.h create mode 100644 src/libwifi/core/frame/frame.c create mode 100644 src/libwifi/core/frame/frame.h create mode 100644 src/libwifi/core/frame/management/action.h create mode 100644 src/libwifi/core/frame/management/assoc_request.h create mode 100644 src/libwifi/core/frame/management/assoc_response.h create mode 100644 src/libwifi/core/frame/management/atim.h create mode 100644 src/libwifi/core/frame/management/authentication.h create mode 100644 src/libwifi/core/frame/management/beacon.h create mode 100644 src/libwifi/core/frame/management/common.h create mode 100644 src/libwifi/core/frame/management/deauthentication.h create mode 100644 src/libwifi/core/frame/management/disassociation.h create mode 100644 src/libwifi/core/frame/management/probe_request.h create mode 100644 src/libwifi/core/frame/management/probe_response.h create mode 100644 src/libwifi/core/frame/management/reassoc_request.h create mode 100644 src/libwifi/core/frame/management/reassoc_response.h create mode 100644 src/libwifi/core/frame/management/timing_ad.h create mode 100644 src/libwifi/core/frame/tag.c create mode 100644 src/libwifi/core/frame/tag.h create mode 100644 src/libwifi/core/frame/tag_iterator.c create mode 100644 src/libwifi/core/frame/tag_iterator.h create mode 100644 src/libwifi/core/misc/byteswap.h create mode 100644 src/libwifi/core/misc/epoch.c create mode 100644 src/libwifi/core/misc/epoch.h create mode 100644 src/libwifi/core/misc/llc.h create mode 100644 src/libwifi/core/misc/radiotap.h create mode 100644 src/libwifi/core/misc/security.h create mode 100644 src/libwifi/core/misc/types.h create mode 100644 src/libwifi/core/radiotap/COPYING create mode 100644 src/libwifi/core/radiotap/platform.h create mode 100644 src/libwifi/core/radiotap/radiotap.c create mode 100644 src/libwifi/core/radiotap/radiotap.h create mode 100644 src/libwifi/core/radiotap/radiotap_iter.h create mode 100644 src/libwifi/gen/control/cts.c create mode 100644 src/libwifi/gen/control/cts.h create mode 100644 src/libwifi/gen/control/rts.c create mode 100644 src/libwifi/gen/control/rts.h create mode 100644 src/libwifi/gen/management/action.c create mode 100644 src/libwifi/gen/management/action.h create mode 100644 src/libwifi/gen/management/assoc_request.c create mode 100644 src/libwifi/gen/management/assoc_request.h create mode 100644 src/libwifi/gen/management/assoc_response.c create mode 100644 src/libwifi/gen/management/assoc_response.h create mode 100644 src/libwifi/gen/management/atim.c create mode 100644 src/libwifi/gen/management/atim.h create mode 100644 src/libwifi/gen/management/authentication.c create mode 100644 src/libwifi/gen/management/authentication.h create mode 100644 src/libwifi/gen/management/beacon.c create mode 100644 src/libwifi/gen/management/beacon.h create mode 100644 src/libwifi/gen/management/common.h create mode 100644 src/libwifi/gen/management/deauthentication.c create mode 100644 src/libwifi/gen/management/deauthentication.h create mode 100644 src/libwifi/gen/management/disassociation.c create mode 100644 src/libwifi/gen/management/disassociation.h create mode 100644 src/libwifi/gen/management/probe_request.c create mode 100644 src/libwifi/gen/management/probe_request.h create mode 100644 src/libwifi/gen/management/probe_response.c create mode 100644 src/libwifi/gen/management/probe_response.h create mode 100644 src/libwifi/gen/management/reassoc_request.c create mode 100644 src/libwifi/gen/management/reassoc_request.h create mode 100644 src/libwifi/gen/management/reassoc_response.c create mode 100644 src/libwifi/gen/management/reassoc_response.h create mode 100644 src/libwifi/gen/management/timing_ad.c create mode 100644 src/libwifi/gen/management/timing_ad.h create mode 100644 src/libwifi/gen/misc/radiotap.c create mode 100644 src/libwifi/gen/misc/radiotap.h create mode 100644 src/libwifi/parse/data/data.c create mode 100644 src/libwifi/parse/data/data.h create mode 100644 src/libwifi/parse/data/eapol.c create mode 100644 src/libwifi/parse/data/eapol.h create mode 100644 src/libwifi/parse/management/assoc_request.c create mode 100644 src/libwifi/parse/management/assoc_request.h create mode 100644 src/libwifi/parse/management/assoc_response.c create mode 100644 src/libwifi/parse/management/assoc_response.h create mode 100644 src/libwifi/parse/management/beacon.c create mode 100644 src/libwifi/parse/management/beacon.h create mode 100644 src/libwifi/parse/management/common.c create mode 100644 src/libwifi/parse/management/common.h create mode 100644 src/libwifi/parse/management/deauthentication.c create mode 100644 src/libwifi/parse/management/deauthentication.h create mode 100644 src/libwifi/parse/management/disassociation.c create mode 100644 src/libwifi/parse/management/disassociation.h create mode 100644 src/libwifi/parse/management/probe_request.c create mode 100644 src/libwifi/parse/management/probe_request.h create mode 100644 src/libwifi/parse/management/probe_response.c create mode 100644 src/libwifi/parse/management/probe_response.h create mode 100644 src/libwifi/parse/management/reassoc_request.c create mode 100644 src/libwifi/parse/management/reassoc_request.h create mode 100644 src/libwifi/parse/management/reassoc_response.c create mode 100644 src/libwifi/parse/management/reassoc_response.h create mode 100644 src/libwifi/parse/misc/radiotap.c create mode 100644 src/libwifi/parse/misc/radiotap.h create mode 100644 src/libwifi/parse/misc/security.c create mode 100644 src/libwifi/parse/misc/security.h create mode 100644 test/CMakeLists.txt create mode 100644 test/pcaps/assoc_req.pcap create mode 100644 test/pcaps/assoc_resp.pcap create mode 100644 test/pcaps/auth.pcap create mode 100644 test/pcaps/beacons_with_221.pcap create mode 100644 test/pcaps/deauth.pcap create mode 100644 test/pcaps/deauth_with_221.pcap create mode 100644 test/pcaps/disassoc.pcap create mode 100644 test/pcaps/probe_req.pcap create mode 100644 test/pcaps/probe_resp_with_221.pcap create mode 100644 test/pcaps/reassoc_req.pcap create mode 100644 test/pcaps/reassoc_resp.pcap create mode 100644 test/src/.clang-format create mode 100644 test/src/helpers.c create mode 100644 test/src/helpers.h create mode 100644 test/src/test_generation.c create mode 100644 test/src/test_misc.c create mode 100644 test/src/test_parsing.c diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..cce8123 --- /dev/null +++ b/.clang-format @@ -0,0 +1,8 @@ +--- +BasedOnStyle: LLVM +IndentWidth: '4' +SpaceAfterCStyleCast: 'true' +ColumnLimit: 110 +AllowShortFunctionsOnASingleLine: None +IndentCaseLabels: 'true' +... diff --git a/.github/workflows/x86_64.yml b/.github/workflows/x86_64.yml new file mode 100644 index 0000000..844a109 --- /dev/null +++ b/.github/workflows/x86_64.yml @@ -0,0 +1,27 @@ +name: libwifi (64-Bit) + +on: [push] + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Create Build Environment + run: cmake -E make_directory ${{github.workspace}}/build + + - name: Configure CMake + shell: bash + working-directory: ${{github.workspace}}/build + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE + + - name: Build X86_64 + working-directory: ${{github.workspace}}/build + shell: bash + run: cmake --build . --config $BUILD_TYPE diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dbbe0da --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# Binaries +*.a +*.o +*.so* + +# Build +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps +CMakeUserPresets.json +*-prefix/ + +# Output +build/ +tests/build/ diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..8c7299c --- /dev/null +++ b/AUTHORS @@ -0,0 +1,10 @@ +# This is the list of libwifi's significant contributors. +# +# This does not necessarily list everyone who has contributed code, +# especially since many employees of one corporation may be contributing. +# To see the full list of contributors, see the revision history in +# source control. +Marc Egerton +Sebastian Kinne +Henry Pitcairn +Hak5 LLC diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..3a94d82 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,51 @@ +cmake_minimum_required(VERSION 3.18) + +project(wifi DESCRIPTION "802.11 Parsing / Generation library" VERSION 0.1) + +execute_process(COMMAND git rev-parse --abbrev-ref HEAD OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE GITBRANCH) +execute_process(COMMAND git log -1 --pretty=format:%h OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE GITHASH) +execute_process(COMMAND date OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE BUILDTIME) +set(LIBWIFI_VERSION "0.0.1") + +message(" ") +message(" _ _ _ _ __ _ ") +message("| |(_)| | (_) / _|(_) ") +message("| | _ | |__ __ __ _ | |_ _ ") +message("| || || '_ \\ \\ \\ /\\ / /| || _|| | ") +message("| || || |_| | \\ V V / | || | | | ") +message("|_||_||_.__/ \\_/\\_/ |_||_| |_| ") +message("-----------------------------------") +message("802.11 Parsing / Generation Library") +message("Version: ${LIBWIFI_VERSION}, Git: ${GITBRANCH} (${GITHASH}), Time: ${BUILDTIME}") +message(" ") + +file(GLOB_RECURSE libwifi_src + "src/libwifi/*.h" + "src/libwifi/*.c" +) + +set(CMAKE_C_COMPILER "/usr/bin/clang") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu17") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic -Wno-language-extension-token") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-prototypes -Wstrict-prototypes") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-strong") + +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + message("Building as Debug") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb -O0") +endif(CMAKE_BUILD_TYPE STREQUAL "Debug") + +add_library(wifi SHARED ${libwifi_src}) + +set_target_properties(wifi PROPERTIES LINKER_LANGUAGE C) +set_target_properties(wifi PROPERTIES VERSION ${LIBWIFI_VERSION}) +set_target_properties(wifi PROPERTIES SOVERSION 0) +set_target_properties(wifi PROPERTIES PUBLIC_HEADER src/libwifi.h) + +install(DIRECTORY src/libwifi/core/ DESTINATION /usr/include/libwifi/core FILES_MATCHING PATTERN "*.h") +install(DIRECTORY src/libwifi/parse/ DESTINATION /usr/include/libwifi/parse FILES_MATCHING PATTERN "*.h") +install(DIRECTORY src/libwifi/gen/ DESTINATION /usr/include/libwifi/gen FILES_MATCHING PATTERN "*.h") +install(TARGETS wifi LIBRARY DESTINATION /usr/lib PUBLIC_HEADER DESTINATION /usr/include) + +add_custom_target(uninstall COMMAND rm -rf /usr/include/libwifi; rm -rf /usr/include/libwifi.h) diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..1b7fb0a --- /dev/null +++ b/COPYING @@ -0,0 +1,15 @@ +/* Copyright 2021 The libwifi Authors +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..27bc874 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016 The libwifi Authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..2be5699 --- /dev/null +++ b/README.md @@ -0,0 +1,88 @@ +# libwifi +802.11 Parsing / Generation library + +| Build Status | OS | Architecture | +| ---------------------------------------------------------------------------------- | ------| ------------ | +|![X86_64](https://github.com/libwifi/libwifi/actions/workflows/x86_64.yml/badge.svg) | Linux | x86_64 | + +## What is this? +libwifi is a C library with a permissive license for generating and parsing a wide variety of 802.11 wireless frames (see the [Feature Checklist](#feature-checklist) below) on Linux with a few lines of straight forward code (see the [Examples section](#examples) below). + +It is written with a simple-to-use approach while also exposing features that allow more advanced use, with clean and readable code being a priority. Other goals of the library include cross-architecture support, clean compilation without warnings and strict error checking. + +The library is fully documented with code comments in both the headers files and the code files, and also has doxygen HTML documentation in `docs/html`. + +## Building and Installing +### Linux +``` +$ mkdir build +$ cd build +$ cmake .. +$ make +$ sudo make install +``` + +## Examples +Some examples are available in the `examples/` directory, which show the general flow of how libwifi is used to generate and parse different types of 802.11 frame. + +## Feature Checklist +- Generation + - [X] Radiotap Header + - Management + - [X] Association Request + - [X] Association Response + - [X] Reassociation Request + - [X] Ressociation Response + - [X] Probe Request + - [X] Probe Response + - [X] Timing Advertisement + - [X] Beacon + - [X] ATIM + - [X] Disassociation + - [X] Deauthentication + - [X] Action + - [X] Action No ACK + - Control + - [X] RTS (Request-to-Send) + - [X] CTS (Clear-to-Send) + - Data + - [ ] Data Frame + - [ ] QoS Data Frame + - [ ] EAPOL + +- Parsing + - [X] Radiotap Header + - Management + - [X] Association Request + - [X] Association Response + - [X] Reassociation Request + - [X] Ressociation Response + - [X] Probe Request + - [X] Probe Response + - [ ] Timing Advertisement + - [X] Beacon + - [ ] ATIM + - [X] Disassociation + - [X] Deauthentication + - [ ] Action + - [ ] Action No ACK + - Control + - [ ] RTS (Request-to-Send) + - [ ] CTS (Clear-to-Send) + - Data + - [X] Data Frame (Partial) + - [X] QoS Data Frame (Partial) + - [X] EAPOL + +## Running Tests +``` +$ cd tests/ +$ mkdir build +$ cd build +$ cmake .. +$ make +$ sudo iw set type monitor && sudo ip link set dev up +$ ./test-program +``` + + diff --git a/benchmark/Makefile b/benchmark/Makefile new file mode 100644 index 0000000..6dd995d --- /dev/null +++ b/benchmark/Makefile @@ -0,0 +1,9 @@ +CC=clang +CFLAGS=-Wall -Werror -O3 -o benchmark_beacon +LDFLAGS=-lpcap -lwifi + +benchmark_beacon: benchmark_beacon.o + $(CC) $(CFLAGS) benchmark_beacon.c $(LDFLAGS) + +clean: + rm benchmark_beacon *.o diff --git a/benchmark/benchmark_beacon.c b/benchmark/benchmark_beacon.c new file mode 100644 index 0000000..d769be8 --- /dev/null +++ b/benchmark/benchmark_beacon.c @@ -0,0 +1,37 @@ +#include + +#include +#include + +// A simple 802.11 Beacon with an SSID and a Channel tag +#define BEACON_FRAME "\x80\x00\x00\x00\xff\xff\xff\xff" \ + "\xff\xff\x00\x20\x91\x11\x22\x33" \ + "\x00\x00\x00\x00\x00\x00\x70\x56" \ + "\xc6\x90\x20\xe7\x7b\x01\x00\x00" \ + "\x88\x00\x01\x00\x00\x0e\x6c\x69" \ + "\x62\x77\x69\x66\x69\x2d\x62\x65" \ + "\x61\x63\x6f\x6e\x03\x01\x0b" + +int main(void) { + float times[12] = {0}; + + for (int i = 0; i < 12; i++) { + float startTime = (float)clock() / CLOCKS_PER_SEC; + + struct libwifi_frame frame; + struct libwifi_bss bss; + libwifi_get_wifi_frame(&frame, (const unsigned char *)BEACON_FRAME, 56, 0); + libwifi_parse_beacon(&bss, &frame); + + float endTime = (float) clock() / CLOCKS_PER_SEC; + times[i] = (endTime - startTime); + + libwifi_free_bss(&bss); + libwifi_free_wifi_frame(&frame); + } + + for (int i = 0; i < 12; i++) { + printf("Run %d:\t%9.7f Seconds\n", i+1, times[i]); + } +} + diff --git a/examples/generate_beacon/README.md b/examples/generate_beacon/README.md new file mode 100644 index 0000000..4b7103d --- /dev/null +++ b/examples/generate_beacon/README.md @@ -0,0 +1,19 @@ +# Generating 802.11 Beacons +This example shows the reader how to generate an 802.11 Beacon, with an SSID and Channel element. It also adds a tagged parameter with the string "libwifi-tag" inside. + +# Building and Using +``` +>> cd examples/generate_beacon/ +>> make +clang -Wall -Werror -O3 -o generate_beacon -c -o generate_beacon.o generate_beacon.c +clang -Wall -Werror -O3 -o generate_beacon generate_beacon.c -lpcap -lwifi +>> ./generate_beacon --file beacon.pcap +[+] Setup Complete +[*] Creating Beacon Frame +[*] Writing Beacon Frame to pcap +>> tshark -r beacon.pcap + 1 0.000000 ca:38:6d:6d:3f:bd → Broadcast 802.11 78 Beacon frame, SN=1383, FN=0, Flags=........, BI=100, SSID=libwifi-beacon +>> +``` +# Output +![image](https://user-images.githubusercontent.com/4153572/143600844-ce7dee11-46b0-40a5-a12c-881d79bd584d.png) diff --git a/examples/generate_beacon/generate_beacon.c b/examples/generate_beacon/generate_beacon.c new file mode 100644 index 0000000..2dad709 --- /dev/null +++ b/examples/generate_beacon/generate_beacon.c @@ -0,0 +1,80 @@ +#include + +#include + +#include +#include +#include +#include +#include +#include + +pcap_dumper_t *filedumper = NULL; + +void create_write_beacon() { + printf("[*] Creating Beacon Frame\n"); + struct libwifi_beacon beacon = {0}; + unsigned char transmitter[6] = {0}; + + libwifi_random_mac(transmitter); + unsigned char receiver[6] = "\xFF\xFF\xFF\xFF\xFF\xFF"; + + libwifi_create_beacon(&beacon, receiver, transmitter, "libwifi-beacon", 6); + libwifi_quick_add_tag(&beacon.tags, TAG_VENDOR_SPECIFIC, + (unsigned char *) "libwifi-tag", strlen("libwifi-tag")); + + unsigned char *buf = NULL; + size_t buf_len = libwifi_get_beacon_length(&beacon); + buf = malloc(buf_len); + if (buf == NULL) { + fprintf(stderr, "[!] Couldn't allocate buffer for beacon dump.\n"); + exit(EXIT_FAILURE); + } + memset(buf, 0, buf_len); + libwifi_dump_beacon(&beacon, buf, buf_len); + + printf("[*] Writing Beacon Frame to pcap\n"); + struct pcap_pkthdr pkt_hdr = {0}; + struct timeval tv = {0}; + pkt_hdr.caplen = buf_len; + pkt_hdr.len = buf_len; + gettimeofday(&tv, NULL); + pkt_hdr.ts = tv; + pcap_dump((unsigned char *) filedumper, &pkt_hdr, buf); +} + +void helpexit() { + fprintf(stderr, "[!] Usage: ./generate_beacon --file \n"); + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) { + pcap_t *handle = NULL; + char errbuf[PCAP_ERRBUF_SIZE] = {0}; + FILE *pcapfile = NULL; + + if (argc < 2) { + helpexit(); + } + if (strcmp(argv[1], "--file") == 0) { + pcapfile = fopen(argv[2], "w+"); + if ((handle = pcap_open_dead(DLT_IEEE802_11, BUFSIZ)) == NULL) { + fprintf(stderr, "[!] Error opening dead capture (%s)\n", errbuf); + exit(EXIT_FAILURE); + } + if ((filedumper = pcap_dump_fopen(handle, pcapfile)) == NULL) { + fprintf(stderr, "[!] Error opening file %s (%s)\n", argv[2], errbuf); + exit(EXIT_FAILURE); + } + } else { + helpexit(); + } + + printf("[+] Setup Complete\n"); + + create_write_beacon(); + + pcap_dump_close(filedumper); + pcap_close(handle); + return 0; +} diff --git a/examples/generate_rtscts/README.md b/examples/generate_rtscts/README.md new file mode 100644 index 0000000..a7db7c2 --- /dev/null +++ b/examples/generate_rtscts/README.md @@ -0,0 +1,23 @@ +# Generating 802.11 RTS and CTS Frames +This example shows the reader how to generate an RTS and a CTS Frame, with a random transmitter and a 32ms duration. + +# Building and Using +``` +>> cd examples/generate_rtscts/ +>> make +clang -Wall -Werror -O3 -o generate_rtscts -c -o generate_rtscts.o generate_rtscts.c +clang -Wall -Werror -O3 -o generate_rtscts generate_rtscts.c -lpcap -lwifi +>> ./generate_rtscts --file rtscts.pcap +[+] Setup Complete +[*] Creating RTS Frame +[*] Writing RTS Frame to pcap +[*] Creating CTS Frame +[*] Writing CTS Frame to pcap +>> tshark -r rtscts.pcap + 1 0.000000 J125Nati_aa:bb:cc (00:20:91:aa:bb:cc) (TA) → Broadcast (ff:ff:ff:ff:ff:ff) (RA) 802.11 16 Request-to-send, Flags=........ + 2 0.000008 → Broadcast (ff:ff:ff:ff:ff:ff) (RA) 802.11 10 Clear-to-send, Flags=........ +>> +``` + +# Output +![image](https://user-images.githubusercontent.com/4153572/143601868-da7e9c99-2534-4fe6-9608-68f5af1ad882.png) diff --git a/examples/generate_rtscts/generate_rtscts.c b/examples/generate_rtscts/generate_rtscts.c new file mode 100644 index 0000000..f449a06 --- /dev/null +++ b/examples/generate_rtscts/generate_rtscts.c @@ -0,0 +1,78 @@ +#include + +#include + +#include +#include +#include +#include +#include +#include + +pcap_dumper_t *filedumper = NULL; + +void create_write_rtscts() { + printf("[*] Creating RTS Frame\n"); + struct libwifi_rts rts = {0}; + unsigned char transmitter[6] = "\x00\x20\x91\xAA\xBB\xCC"; + unsigned char receiver[6] = "\xFF\xFF\xFF\xFF\xFF\xFF"; + libwifi_create_rts(&rts, transmitter, receiver, 32); + + printf("[*] Writing RTS Frame to pcap\n"); + struct pcap_pkthdr pkt_hdr = {0}; + struct timeval tv = {0}; + pkt_hdr.caplen = sizeof(struct libwifi_rts); + pkt_hdr.len = sizeof(struct libwifi_rts); + gettimeofday(&tv, NULL); + pkt_hdr.ts = tv; + pcap_dump((unsigned char *) filedumper, &pkt_hdr, (const unsigned char *) &rts); + + printf("[*] Creating CTS Frame\n"); + struct libwifi_cts cts = {0}; + libwifi_create_cts(&cts, receiver, 32); + + printf("[*] Writing CTS Frame to pcap\n"); + memset(&pkt_hdr, 0, sizeof(struct pcap_pkthdr)); + memset(&tv, 0, sizeof(struct timeval)); + pkt_hdr.caplen = sizeof(struct libwifi_cts); + pkt_hdr.len = sizeof(struct libwifi_cts); + gettimeofday(&tv, NULL); + pkt_hdr.ts = tv; + pcap_dump((unsigned char *) filedumper, &pkt_hdr, (const unsigned char *) &cts); +} + +void helpexit() { + fprintf(stderr, "[!] Usage: ./generate_beacon --file \n"); + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) { + pcap_t *handle = NULL; + char errbuf[PCAP_ERRBUF_SIZE] = {0}; + FILE *pcapfile = NULL; + + if (argc < 2) { + helpexit(); + } + if (strcmp(argv[1], "--file") == 0) { + pcapfile = fopen(argv[2], "w+"); + if ((handle = pcap_open_dead(DLT_IEEE802_11, BUFSIZ)) == NULL) { + fprintf(stderr, "[!] Error opening dead capture (%s)\n", errbuf); + exit(EXIT_FAILURE); + } + if ((filedumper = pcap_dump_fopen(handle, pcapfile)) == NULL) { + fprintf(stderr, "[!] Error opening file %s (%s)\n", argv[2], errbuf); + exit(EXIT_FAILURE); + } + } else { + helpexit(); + } + + printf("[+] Setup Complete\n"); + + create_write_rtscts(); + + pcap_dump_close(filedumper); + pcap_close(handle); + return 0; +} diff --git a/examples/parse_beacon/README.md b/examples/parse_beacon/README.md new file mode 100644 index 0000000..a9b085b --- /dev/null +++ b/examples/parse_beacon/README.md @@ -0,0 +1,65 @@ +# Parsing 802.11 Beacon Frames +This example shows the reader how to parse 802.11 Beacons from a pcap, outputting the SSID, BSSID, Channel, Security Information, and more to the terminal. + +# Building and Using +``` +>> cd examples/parse_beacon/ +>> make +clang -Wall -Werror -O3 -o parse_beacon -c -o parse_beacon.o parse_beacon.c +clang -Wall -Werror -O3 -o parse_beacon parse_beacon.c -lpcap -lwifi +>> ./parse_beacon --file ~/beacon.pcap [1/789] +[+] Setup Complete +ESSID: libwifi-wpa2/3 +BSSID: 7e:fc:5e:51:93:31 +Receiver: ff:ff:ff:ff:ff:ff +Transmitter: 7e:fc:5e:51:93:31 +Channel: 11 +WPS: No +Encryption: WPA3, WPA2 + Group Ciphers: CCMP128 + Pairwise Ciphers: CCMP128 + Auth Key Suites: PSK, SAE + MFP Capable: Yes +Tagged Parameters: + Tag: 0 (Size: 14) + 14 bytes of Tag Data: 6c 69 62 77 69 66 69 2d 77 70 61 32 2f 33 + Tag: 1 (Size: 8) + 8 bytes of Tag Data: 82 84 8b 96 24 30 48 6c + Tag: 3 (Size: 1) + 1 bytes of Tag Data: 0b + Tag: 5 (Size: 4) + 4 bytes of Tag Data: 00 02 00 00 + Tag: 7 (Size: 6) + 6 bytes of Tag Data: 47 42 20 01 0d 80 + Tag: 32 (Size: 1) + 1 bytes of Tag Data: 00 + Tag: 35 (Size: 2) + 2 bytes of Tag Data: 10 00 + Tag: 42 (Size: 1) + 1 bytes of Tag Data: 00 + Tag: 50 (Size: 4) + 4 bytes of Tag Data: 0c 12 18 60 + Tag: 48 (Size: 24) + 16 bytes of Tag Data: 01 00 00 0f ac 04 01 00 00 0f ac 04 02 00 00 0f + Tag: 45 (Size: 26) + 16 bytes of Tag Data: 2d 00 1b ff ff 00 00 00 00 00 00 00 00 00 00 00 + Tag: 61 (Size: 22) + 16 bytes of Tag Data: 0b 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + Tag: 127 (Size: 8) + 8 bytes of Tag Data: 04 00 08 00 00 00 00 40 + Tag: 255 (Size: 28) + 16 bytes of Tag Data: 23 01 08 00 1a 00 80 20 20 02 00 0d 00 9e 00 0c + Tag: 255 (Size: 7) + 7 bytes of Tag Data: 24 04 00 00 00 fc ff + Tag: 255 (Size: 14) + 14 bytes of Tag Data: 26 00 03 a4 ff 27 a4 ff 42 43 ff 62 32 ff + Tag: 255 (Size: 4) + 4 bytes of Tag Data: 27 00 00 00 + Tag: 221 (Size: 30) + 16 bytes of Tag Data: 00 90 4c 04 08 bf 0c 32 70 81 0f fa ff 00 00 fa + Tag: 221 (Size: 10) + 10 bytes of Tag Data: 00 10 18 02 00 00 1c 00 00 00 + Tag: 221 (Size: 24) + 16 bytes of Tag Data: 00 50 f2 02 01 01 00 00 03 a4 00 00 27 a4 00 00 +>> +``` diff --git a/examples/parse_beacon/parse_beacon.c b/examples/parse_beacon/parse_beacon.c new file mode 100644 index 0000000..4e320b7 --- /dev/null +++ b/examples/parse_beacon/parse_beacon.c @@ -0,0 +1,158 @@ +#include + +#include + +#include +#include +#include + +static int has_radiotap = 0; + +int print_tag_info(unsigned char *tag_data, size_t tag_data_len) { + // Initialise a libwifi_tag_iterator + struct libwifi_tag_iterator it = {0}; + if (libwifi_tag_iterator_init(&it, tag_data, tag_data_len) != 0) { + return -1; + } + + do { + printf("\tTag: %d (Size: %d)\n", it.tag_header->tag_num, it.tag_header->tag_len); + + int max_size = 16; + if (it.tag_header->tag_len < 16) { + max_size = it.tag_header->tag_len; + } + printf("\t%d bytes of Tag Data: ", max_size); + for (size_t i = 0; i < max_size; i++) { + printf("%02x ", it.tag_data[i]); + } + printf("\n"); + } while (libwifi_tag_iterator_next(&it) != -1); + + return 0; +} + +void handle_pkt(unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet) { + unsigned long data_len = header->caplen; + unsigned char *data = (unsigned char *) packet; + + // Initialise a libwifi_frame struct and populate it + struct libwifi_frame frame = {0}; + int ret = libwifi_get_wifi_frame(&frame, data, data_len, has_radiotap); + if (ret != 0) { + return; + } + + // Ensure the frame is a Beacon frame + if (frame.frame_control.type == TYPE_MANAGEMENT && frame.frame_control.subtype == SUBTYPE_BEACON) { + // Initalise a libwifi_bss struct and populate it with the data from the sniffed frame + struct libwifi_bss bss = {0}; + ret = libwifi_parse_beacon(&bss, &frame); + if (ret != 0) { + return; + } + + // Print basic information from the new struct + printf("ESSID: %s\n", bss.hidden ? "(hidden)" : bss.ssid); + printf("BSSID: " MACSTR "\n", MAC2STR(bss.bssid)); + printf("Receiver: " MACSTR "\n", MAC2STR(bss.receiver)); + printf("Transmitter: " MACSTR "\n", MAC2STR(bss.transmitter)); + printf("Channel: %d\n", bss.channel); + printf("WPS: %s\n", bss.wps ? "Yes" : "No"); + + // Initialse a char buffer of length LIBWIFI_SECURITY_BUF_LEN, and use libwifi to + // write the security suite (WEP, WPA, etc) to it, before printing it. + char sec_buf[LIBWIFI_SECURITY_BUF_LEN]; + libwifi_get_security_type(&bss, sec_buf); + printf("Encryption: %s\n", sec_buf); + + // We can re-use the sec_buf buffer for other security related items, since libwifi + // will take care of the memory for us. + // We'll use the same buffer to get the WPA/2/3 group ciphers from the beacon, if any. + libwifi_get_group_ciphers(&bss, sec_buf); + printf("\tGroup Ciphers: %s\n", sec_buf); + + // ... and the same for the pairwise ciphers + libwifi_get_pairwise_ciphers(&bss, sec_buf); + printf("\tPairwise Ciphers: %s\n", sec_buf); + + // ... and the same for the authentication maagement key suites + libwifi_get_auth_key_suites(&bss, sec_buf); + printf("\tAuth Key Suites: %s\n", sec_buf); + + // Check for enabled RSN Capabilities. In this example, we will check for the + // presence of Management Frame Protection (802.11w) + if (bss.rsn_info.rsn_capabilities & LIBWIFI_RSN_CAPAB_MFP_CAPABLE) { + printf("\tMFP Capable: Yes\n"); + } + if (bss.rsn_info.rsn_capabilities & LIBWIFI_RSN_CAPAB_MFP_REQUIRED) { + printf("\tMFP Required: Yes\n"); + } + + // If any tagged parameters are available for this frame, we can iterate through them + // since libwifi will automatically find them. + if (bss.tags.length) { + printf("Tagged Parameters:\n"); + print_tag_info(bss.tags.parameters, bss.tags.length); + } else { + printf("Tagged Parameters: None\n"); + } + + // Cleanup the libwifi bss + libwifi_free_bss(&bss); + } + + printf("\n"); + + // Clean up the libwifi frame + libwifi_free_wifi_frame(&frame); +} + +void helpexit() { + fprintf(stderr, "[!] Usage: ./parse_eapol --file \n"); + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) { + struct bpf_program *filter = NULL; + pcap_t *handle = NULL; + pcap_dumper_t *dumper = NULL; + char errbuf[PCAP_ERRBUF_SIZE]; + + if (argc < 2) { + helpexit(); + } + if (strcmp(argv[1], "--file") == 0) { + if ((handle = pcap_open_offline(argv[2], errbuf)) == NULL) { + fprintf(stderr, "[!] Error opening file %s (%s)\n", argv[2], errbuf); + exit(EXIT_FAILURE); + } + } else { + helpexit(); + } + + int linktype = pcap_datalink(handle); + if (linktype == DLT_IEEE802_11_RADIO) { + has_radiotap = 1; + } + if (linktype != DLT_IEEE802_11 && linktype != DLT_IEEE802_11_RADIO) { + fprintf(stderr, "[!] 802.11 and radiotap headers not provided (%d)\n", pcap_datalink(handle)); + pcap_close(handle); + exit(EXIT_FAILURE); + } + + if ((filter = malloc(sizeof(struct bpf_program))) == NULL) { + fprintf(stderr, "[!] There was an error allocating memory for the filter.\n"); + pcap_close(handle); + exit(EXIT_FAILURE); + } + + printf("[+] Setup Complete\n"); + + dumper = pcap_dump_open(handle, "/tmp/parse_beacon.pcap"); + pcap_loop(handle, -1 /*INFINITY*/, &handle_pkt, (unsigned char *) dumper); + + pcap_dump_close(dumper); + pcap_close(handle); + return 0; +} diff --git a/examples/parse_eapol/README.md b/examples/parse_eapol/README.md new file mode 100644 index 0000000..4aa206a --- /dev/null +++ b/examples/parse_eapol/README.md @@ -0,0 +1,74 @@ +# Parsing 802.11 Handshake / EAPOL Frames +This example shows the reader how to parse 802.11 Handshakes from a pcap, outputting the EAPOL version, type, length, and data such as Nonce, IV, MIC and EAPOL Key Data. + +# Building and Using +``` +>> cd examples/parse_eapol/ +>> make +clang -Wall -Werror -O3 -o parse_eapol -c -o parse_eapol.o parse_eapol.c +clang -Wall -Werror -O3 -o parse_eapol parse_eapol.c -lpcap -lwifi +>> ./parse_eapol --file ~/libwifi-handshake.pcap +[+] Setup Complete +WPA Handshake Message: 1 (Message 1) +EAPOL: Version: 2 +EAPOL: Type: 3 +EAPOL: Length: 95 +EAPOL: Descriptor: 2 +EAPOL: Key Info: Information: 0x008a +EAPOL: Key Info: Key Length: 16 +EAPOL: Key Info: Replay Counter: 1 +EAPOL: Key Info: Nonce: 43 79 98 09 6a 0e dc 73 8d 44 3b 55 ce b5 47 2c fd 39 0c 87 51 e4 f0 77 d9 5b 5c e1 dc 59 bd 75 +EAPOL: Key Info: IV: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +EAPOL: Key Info: RSC: 00 00 00 00 00 00 00 00 +EAPOL: Key Info: ID: 00 00 00 00 00 00 00 00 +EAPOL: Key Info: MIC: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +EAPOL: Key Info: Key Data Length: 0 + +WPA Handshake Message: 2 (Message 2) +EAPOL: Version: 1 +EAPOL: Type: 3 +EAPOL: Length: 123 +EAPOL: Descriptor: 2 +EAPOL: Key Info: Information: 0x010a +EAPOL: Key Info: Key Length: 0 +EAPOL: Key Info: Replay Counter: 1 +EAPOL: Key Info: Nonce: de ed a2 79 e3 c4 96 ba 25 8b ba 84 76 0a 00 69 2e 2c 10 41 24 1a f3 6f 70 9a 4b db 5f 93 47 80 +EAPOL: Key Info: IV: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +EAPOL: Key Info: RSC: 00 00 00 00 00 00 00 00 +EAPOL: Key Info: ID: 00 00 00 00 00 00 00 00 +EAPOL: Key Info: MIC: 6c 23 fe 8d 68 35 c9 5a 77 82 25 4b 56 41 70 71 +EAPOL: Key Info: Key Data Length: 28 +EAPOL: Key Info: Key Data: 30 1a 01 00 00 0f ac 04 01 00 00 0f ac 04 01 00 00 0f ac 02 80 00 00 00 00 0f ac 06 + +WPA Handshake Message: 4 (Message 3) +EAPOL: Version: 2 +EAPOL: Type: 3 +EAPOL: Length: 183 +EAPOL: Descriptor: 2 +EAPOL: Key Info: Information: 0x13ca +EAPOL: Key Info: Key Length: 16 +EAPOL: Key Info: Replay Counter: 2 +EAPOL: Key Info: Nonce: 43 79 98 09 6a 0e dc 73 8d 44 3b 55 ce b5 47 2c fd 39 0c 87 51 e4 f0 77 d9 5b 5c e1 dc 59 bd 75 +EAPOL: Key Info: IV: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +EAPOL: Key Info: RSC: 00 00 00 00 00 00 00 00 +EAPOL: Key Info: ID: 00 00 00 00 00 00 00 00 +EAPOL: Key Info: MIC: b7 e7 f1 60 f8 cf 3f ec 8f b3 c5 29 e4 a1 d0 05 +EAPOL: Key Info: Key Data Length: 88 +EAPOL: Key Info: Key Data: 5e b1 a7 ef db 8d 55 06 d5 c8 89 e7 ca 55 ea cf f5 fa 08 18 ef 4e 46 6e b6 3e 62 d1 30 e7 e5 38 ef 2b 37 61 55 03 9e 84 31 75 3e 44 bd 87 12 9c 94 52 db fb 6a 58 4e 1f 94 e0 16 a9 e9 cb 36 48 c8 ed 20 d3 ff 37 a6 7e 12 3f 0b fc 2c a6 cb 72 c3 6a bf 01 32 b1 6e 1b + +WPA Handshake Message: 8 (Message 4) +EAPOL: Version: 1 +EAPOL: Type: 3 +EAPOL: Length: 95 +EAPOL: Descriptor: 2 +EAPOL: Key Info: Information: 0x030a +EAPOL: Key Info: Key Length: 0 +EAPOL: Key Info: Replay Counter: 2 +EAPOL: Key Info: Nonce: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +EAPOL: Key Info: IV: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +EAPOL: Key Info: RSC: 00 00 00 00 00 00 00 00 +EAPOL: Key Info: ID: 00 00 00 00 00 00 00 00 +EAPOL: Key Info: MIC: 13 6e 07 be 17 51 01 e2 03 5d 4c b1 43 e1 4b c7 +EAPOL: Key Info: Key Data Length: 0 +>> +``` diff --git a/examples/parse_eapol/parse_eapol.c b/examples/parse_eapol/parse_eapol.c new file mode 100644 index 0000000..259ee5f --- /dev/null +++ b/examples/parse_eapol/parse_eapol.c @@ -0,0 +1,140 @@ +#include + +#include + +#include +#include +#include + +static int has_radiotap = 0; + +void handle_pkt(unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet) { + unsigned long data_len = header->caplen; + unsigned char *data = (unsigned char *) packet; + + // Initialise a libwifi_frame struct and populate it + struct libwifi_frame frame = {0}; + int ret = libwifi_get_wifi_frame(&frame, data, data_len, has_radiotap); + if (ret != 0) { + return; + } + + // Ensure the parsed frame is a data frame + if (frame.frame_control.type == TYPE_DATA) { + // Ensure the parsed data frame is a WPA handshake + if (libwifi_check_wpa_handshake(&frame) > 0) { + // Use libwifi to get the EAPOL message part, and also pretty-print it + int part = libwifi_check_wpa_message(&frame); + printf("WPA Handshake Message: %d (%s)\n", part, libwifi_get_wpa_message_string(&frame)); + + // Initlaise a WPA Authentication Data struct and populate it + struct libwifi_wpa_auth_data data = {0}; + libwifi_get_wpa_data(&frame, &data); + + // Print all of the available WPA Auth data + printf("EAPOL: Version: %d\n", data.version); + printf("EAPOL: Type: %d\n", data.type); + printf("EAPOL: Length: %d\n", data.length); + printf("EAPOL: Descriptor: %d\n", data.descriptor); + printf("EAPOL: Key Info: Information: 0x%04x\n", data.key_info.information); + printf("EAPOL: Key Info: Key Length: %d\n", data.key_info.key_length); + printf("EAPOL: Key Info: Replay Counter: %lu\n", data.key_info.replay_counter); + printf("EAPOL: Key Info: Nonce: "); + for (size_t i = 0; i < sizeof(data.key_info.nonce); ++i) { + printf("%02x ", data.key_info.nonce[i]); + } + printf("\n"); + + printf("EAPOL: Key Info: IV: "); + for (size_t i = 0; i < sizeof(data.key_info.iv); ++i) { + printf("%02x ", data.key_info.iv[i]); + } + printf("\n"); + + printf("EAPOL: Key Info: RSC: "); + for (size_t i = 0; i < sizeof(data.key_info.rsc); ++i) { + printf("%02x ", data.key_info.rsc[i]); + } + printf("\n"); + + printf("EAPOL: Key Info: ID: "); + for (size_t i = 0; i < sizeof(data.key_info.id); ++i) { + printf("%02x ", data.key_info.id[i]); + } + printf("\n"); + + printf("EAPOL: Key Info: MIC: "); + for (size_t i = 0; i < sizeof(data.key_info.mic); ++i) { + printf("%02x ", data.key_info.mic[i]); + } + printf("\n"); + + printf("EAPOL: Key Info: Key Data Length: %d\n", data.key_info.key_data_length); + if (data.key_info.key_data_length) { + printf("EAPOL: Key Info: Key Data: "); + for (size_t i = 0; i < data.key_info.key_data_length; ++i) { + printf("%02x ", data.key_info.key_data[i]); + } + printf("\n"); + } + + // Cleanup the WPA Data + libwifi_free_wpa_data(&data); + + printf("\n"); + } + } + + // Clean up the libwifi frame + libwifi_free_wifi_frame(&frame); +} + +void helpexit() { + fprintf(stderr, "[!] Usage: ./parse_eapol --file \n"); + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) { + struct bpf_program *filter = NULL; + pcap_t *handle = NULL; + pcap_dumper_t *dumper = NULL; + char errbuf[PCAP_ERRBUF_SIZE]; + + if (argc < 2) { + helpexit(); + } + if (strcmp(argv[1], "--file") == 0) { + if ((handle = pcap_open_offline(argv[2], errbuf)) == NULL) { + fprintf(stderr, "[!] Error opening file %s (%s)\n", argv[2], errbuf); + exit(EXIT_FAILURE); + } + } else { + helpexit(); + } + + int linktype = pcap_datalink(handle); + if (linktype == DLT_IEEE802_11_RADIO) { + has_radiotap = 1; + } + if (linktype != DLT_IEEE802_11 && linktype != DLT_IEEE802_11_RADIO) { + fprintf(stderr, "[!] 802.11 and radiotap headers not provided (%d)\n", pcap_datalink(handle)); + pcap_close(handle); + exit(EXIT_FAILURE); + } + + if ((filter = malloc(sizeof(struct bpf_program))) == NULL) { + fprintf(stderr, "[!] There was an error allocating memory for the filter.\n"); + pcap_close(handle); + exit(EXIT_FAILURE); + } + + printf("[+] Setup Complete\n"); + + dumper = pcap_dump_open(handle, "/tmp/parse_eapol.pcap"); + pcap_loop(handle, -1 /*INFINITY*/, &handle_pkt, (unsigned char *) dumper); + + pcap_dump_close(dumper); + pcap_close(handle); + + return 0; +} diff --git a/scripts/generate_entry_header.sh b/scripts/generate_entry_header.sh new file mode 100755 index 0000000..b9e152d --- /dev/null +++ b/scripts/generate_entry_header.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +if [[ ! -d "src/libwifi" ]]; then + echo "[!] You must run this script from the project directory root" + exit 1 +fi + +rm src/libwifi.h +touch src/libwifi.h + +# Generate Header +cat < src/libwifi.h +#ifndef LIBWIFI_H +#define LIBWIFI_H + +#ifdef __cplusplus +extern "C" { +#endif + +$(find src -type f -name '*.h' -printf '%P\n' | sed '/libwifi.h/d' | sort | awk '{print "#include \"" $0 "\""}') + +#ifdef __cplusplus +} +#endif + +#endif /* LIBWIFI_H */ +EOF + +echo "[!] Generated libwifi entry header!" + +exit 0 diff --git a/src/libwifi.h b/src/libwifi.h new file mode 100644 index 0000000..d53789a --- /dev/null +++ b/src/libwifi.h @@ -0,0 +1,75 @@ +#ifndef LIBWIFI_H +#define LIBWIFI_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "libwifi/core/core.h" +#include "libwifi/core/frame/control/cts.h" +#include "libwifi/core/frame/control/rts.h" +#include "libwifi/core/frame/crc.h" +#include "libwifi/core/frame/data/data.h" +#include "libwifi/core/frame/frame.h" +#include "libwifi/core/frame/management/action.h" +#include "libwifi/core/frame/management/assoc_request.h" +#include "libwifi/core/frame/management/assoc_response.h" +#include "libwifi/core/frame/management/atim.h" +#include "libwifi/core/frame/management/authentication.h" +#include "libwifi/core/frame/management/beacon.h" +#include "libwifi/core/frame/management/common.h" +#include "libwifi/core/frame/management/deauthentication.h" +#include "libwifi/core/frame/management/disassociation.h" +#include "libwifi/core/frame/management/probe_request.h" +#include "libwifi/core/frame/management/probe_response.h" +#include "libwifi/core/frame/management/reassoc_request.h" +#include "libwifi/core/frame/management/reassoc_response.h" +#include "libwifi/core/frame/management/timing_ad.h" +#include "libwifi/core/frame/tag.h" +#include "libwifi/core/frame/tag_iterator.h" +#include "libwifi/core/misc/byteswap.h" +#include "libwifi/core/misc/epoch.h" +#include "libwifi/core/misc/llc.h" +#include "libwifi/core/misc/radiotap.h" +#include "libwifi/core/misc/security.h" +#include "libwifi/core/misc/types.h" +#include "libwifi/core/radiotap/platform.h" +#include "libwifi/core/radiotap/radiotap.h" +#include "libwifi/core/radiotap/radiotap_iter.h" +#include "libwifi/gen/control/cts.h" +#include "libwifi/gen/control/rts.h" +#include "libwifi/gen/management/action.h" +#include "libwifi/gen/management/assoc_request.h" +#include "libwifi/gen/management/assoc_response.h" +#include "libwifi/gen/management/atim.h" +#include "libwifi/gen/management/authentication.h" +#include "libwifi/gen/management/beacon.h" +#include "libwifi/gen/management/common.h" +#include "libwifi/gen/management/deauthentication.h" +#include "libwifi/gen/management/disassociation.h" +#include "libwifi/gen/management/probe_request.h" +#include "libwifi/gen/management/probe_response.h" +#include "libwifi/gen/management/reassoc_request.h" +#include "libwifi/gen/management/reassoc_response.h" +#include "libwifi/gen/management/timing_ad.h" +#include "libwifi/gen/misc/radiotap.h" +#include "libwifi/parse/data/data.h" +#include "libwifi/parse/data/eapol.h" +#include "libwifi/parse/management/assoc_request.h" +#include "libwifi/parse/management/assoc_response.h" +#include "libwifi/parse/management/beacon.h" +#include "libwifi/parse/management/common.h" +#include "libwifi/parse/management/deauthentication.h" +#include "libwifi/parse/management/disassociation.h" +#include "libwifi/parse/management/probe_request.h" +#include "libwifi/parse/management/probe_response.h" +#include "libwifi/parse/management/reassoc_request.h" +#include "libwifi/parse/management/reassoc_response.h" +#include "libwifi/parse/misc/radiotap.h" +#include "libwifi/parse/misc/security.h" + +#ifdef __cplusplus +} +#endif + +#endif /* LIBWIFI_H */ diff --git a/src/libwifi/core/core.c b/src/libwifi/core/core.c new file mode 100644 index 0000000..0340a82 --- /dev/null +++ b/src/libwifi/core/core.c @@ -0,0 +1,46 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "core.h" +#include +#include +#include + +/** + * Random MAC addresses, achieved by obtaining 6 bytes of /dev/urandom via getrandom() + */ +void libwifi_random_mac(unsigned char buf[6], unsigned char prefix[3]) { + memset(buf, 0, 6); + if (prefix != NULL) { + memcpy(buf, prefix, 3); + getrandom(buf + 3, 3, 0); + } else { + getrandom(buf, 6, 0); + } +} + +/** + * Dummy linker test function + */ +void libwifi_dummy(void) { + return; +} + +/** + * Version + */ +const char *libwifi_get_version(void) { + return LIBWIFI_VERSION; +} diff --git a/src/libwifi/core/core.h b/src/libwifi/core/core.h new file mode 100644 index 0000000..02e6d45 --- /dev/null +++ b/src/libwifi/core/core.h @@ -0,0 +1,53 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_H +#define LIBWIFI_CORE_H + +#define LIBWIFI_VERSION "0.0.1" + +/** + * Commonly used fixed fields + */ +#define LIBWIFI_BCAST_MAC "\xFF\xFF\xFF\xFF\xFF\xFF" +#define LIBWIFI_ZERO_MAC "\x00\x00\x00\x00\x00\x00" + +/** + * Helpers for MAC Addresses + */ +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + +/** + * Function to randomly generate a MAC address. + * + * @param buf A buffer for the generated MAC to be written to + * @param prefix An optional OUI prefix + */ +void libwifi_random_mac(unsigned char buf[6], unsigned char prefix[3]); + +/** + * Dummy function for linker testing purposes. + */ +void libwifi_dummy(void); + +/** + * Obtain the version of libwifi. + * + * @return The version of the installed libwifi. + */ +const char *libwifi_get_version(void); + +#endif /* LIBWIFI_CORE_H */ diff --git a/src/libwifi/core/frame/control/cts.h b/src/libwifi/core/frame/control/cts.h new file mode 100644 index 0000000..ecf0007 --- /dev/null +++ b/src/libwifi/core/frame/control/cts.h @@ -0,0 +1,35 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_CTS_H +#define LIBWIFI_CORE_CTS_H + +#include "../frame.h" + +/** + * Clear-to-Send Layout + * ─────────────────────────────────── + * ┌─────────────────────────────────┐ + * │ Header │ Bytes: 4 + * ├─────────────────────────────────┤ + * │ Receiver Address │ Bytes: 6 + * └─────────────────────────────────┘ + */ +struct libwifi_cts { + struct libwifi_ctrl_frame_header frame_header; + unsigned char receiver_addr[6]; +}; + +#endif /* LIBWIFI_CORE_CTS_H */ diff --git a/src/libwifi/core/frame/control/rts.h b/src/libwifi/core/frame/control/rts.h new file mode 100644 index 0000000..0fbaacc --- /dev/null +++ b/src/libwifi/core/frame/control/rts.h @@ -0,0 +1,38 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_RTS_H +#define LIBWIFI_CORE_RTS_H + +#include "../frame.h" + +/** + * Request-to-Send Layout + * ─────────────────────────────────── + * ┌─────────────────────────────────┐ + * │ Header │ Bytes: 4 + * ├─────────────────────────────────┤ + * │ Receiver Address │ Bytes: 6 + * ├─────────────────────────────────┤ + * │ Transmitter Address │ Bytes: 4 + * └─────────────────────────────────┘ + */ +struct libwifi_rts { + struct libwifi_ctrl_frame_header frame_header; + unsigned char receiver_addr[6]; + unsigned char transmitter_addr[6]; +}; + +#endif /* LIBWIFI_CORE_RTS_H */ diff --git a/src/libwifi/core/frame/crc.c b/src/libwifi/core/frame/crc.c new file mode 100644 index 0000000..33dae06 --- /dev/null +++ b/src/libwifi/core/frame/crc.c @@ -0,0 +1,63 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "crc.h" +#include "../misc/byteswap.h" + +#include +#include + +/* + * Basic CRC32 implementation for getting the frame check sum of + * a supplied message, usually frame data. + */ +uint32_t libwifi_crc32(const unsigned char *message, int message_len) { + int i, j; + unsigned int byte, crc, mask; + i = 0; + crc = 0xFFFFFFFF; + while (i < message_len) { + byte = message[i]; + crc = crc ^ byte; + for (j = 7; j >= 0; j--) { + mask = -(crc & 1); + crc = (crc >> 1) ^ (0xEDB88320 & mask); + } + i = i + 1; + } + return ~crc; +} + +/* + * Specific function for calculating a frame FCS, byteswapped for the + * host endianess. + */ +uint32_t libwifi_calculate_fcs(const unsigned char *frame, size_t frame_len) { + return BYTESWAP32(libwifi_crc32(frame, frame_len)); +} + +/* + * Verify a frame containing a FCS at the end to the FCS calculated + * by libwifi. + */ +int libwifi_frame_verify(void *frame, size_t frame_len) { + uint32_t oCRC = *((uint32_t *) ((char *) frame + frame_len)); + uint32_t rCRC = libwifi_calculate_fcs(frame, frame_len); + + if (rCRC == oCRC) { + return 1; + } + return 0; +} diff --git a/src/libwifi/core/frame/crc.h b/src/libwifi/core/frame/crc.h new file mode 100644 index 0000000..aab1c4e --- /dev/null +++ b/src/libwifi/core/frame/crc.h @@ -0,0 +1,49 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_CRC_H +#define LIBWIFI_CORE_CRC_H + +#include +#include + +/** + * Calculate the CRC32 sum of a given buffer. + * + * @param message Buffer of data + * @param message_len Length of the data buffer + * @return CRC32 sum of the given buffer + */ +uint32_t libwifi_crc32(const unsigned char *message, int message_len); + +/** + * Calculate the frame checksum for an 802.11 frame. + * + * @param frame An 802.11 frame + * @param frame_len Length of the frame + * @return frame checksum of the frame + */ +uint32_t libwifi_calculate_fcs(const unsigned char *frame, size_t frame_len); + +/** + * Check if the given 802.11 frame has a valid FCS. + * + * @param frame An 802.11 frame with an FCS + * @param frame_len Length of the frame + * @return 1 if verified, 0 if not + */ +int libwifi_frame_verify(void *frame, size_t frame_len); + +#endif /* LIBWIFI_CORE_CRC_H */ diff --git a/src/libwifi/core/frame/data/data.h b/src/libwifi/core/frame/data/data.h new file mode 100644 index 0000000..2eca0ce --- /dev/null +++ b/src/libwifi/core/frame/data/data.h @@ -0,0 +1,32 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_DATA_H +#define LIBWIFI_CORE_DATA_H + +#include + +/** + * Data Frame Layout + * ─────────────────────────────────── + */ +struct libwifi_data { + unsigned char transmitter[6]; + unsigned char receiver[6]; + unsigned char *body; + size_t body_len; +}; + +#endif /* LIBWIFI_CORE_DATA_H */ diff --git a/src/libwifi/core/frame/frame.c b/src/libwifi/core/frame/frame.c new file mode 100644 index 0000000..d885d96 --- /dev/null +++ b/src/libwifi/core/frame/frame.c @@ -0,0 +1,145 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "frame.h" +#include "../../parse/misc/radiotap.h" +#include "../misc/byteswap.h" +#include "../radiotap/radiotap.h" + +#include +#include +#include + +/* + * Turn sniffed data into a libwifi_frame struct for use with other libwifi functions. + * + * Supported frames: + * - Management Frames (Ordered) + * - Management Frames (Unordered) + * - Data Frames + * - QoS Data Frames + * - Control Frames + */ +int libwifi_get_wifi_frame(struct libwifi_frame *fi, const unsigned char *frame, size_t frame_len, + int radiotap) { + union libwifi_frame_header fh = {0}; + size_t header_len = 0; + size_t frame_data_len = frame_len; + unsigned char *frame_data = malloc(frame_data_len); + memcpy(frame_data, (unsigned char *) frame, frame_data_len); + + if (radiotap) { + struct libwifi_radiotap_info rtap_info = {0}; + libwifi_parse_radiotap_info(&rtap_info, frame_data); + + // Skip forward by the length of the radiotap header + frame_data_len -= rtap_info.length; + unsigned char *new_data = malloc(frame_data_len); + memcpy(new_data, frame_data + rtap_info.length, frame_data_len); + free(frame_data); + frame_data = new_data; + + // Remove the FCS from the end of the frame data, if present + if (rtap_info.flags & IEEE80211_RADIOTAP_F_FCS) { + fi->flags |= LIBWIFI_FLAGS_FCS_PRESENT; + frame_data_len -= sizeof(uint32_t); // FCS is 4 bytes wide + frame_data = realloc(frame_data, frame_data_len); + if (frame_data == NULL) { + return -ENOMEM; + } + } + } + + struct libwifi_frame_ctrl *frame_control = (struct libwifi_frame_ctrl *) frame_data; + + switch (frame_control->type) { + case TYPE_DATA: + switch (frame_control->subtype) { + case SUBTYPE_DATA_QOS_DATA: + case SUBTYPE_DATA_QOS_NULL: + case SUBTYPE_DATA_QOS_DATA_CF_ACK: + case SUBTYPE_DATA_QOS_DATA_CF_ACK_CF_POLL: + case SUBTYPE_DATA_QOS_DATA_CF_POLL: + case SUBTYPE_DATA_QOS_CF_ACK_CF_POLL: + case SUBTYPE_DATA_QOS_CF_POLL: + fi->flags |= LIBWIFI_FLAGS_IS_QOS; + break; + } + + if (fi->flags & LIBWIFI_FLAGS_IS_QOS) { + header_len = sizeof(struct libwifi_data_qos_frame_header); + } else { + header_len = sizeof(struct libwifi_data_frame_header); + } + + if (frame_data_len < header_len) { + free(frame_data); + return -EINVAL; + } + + if (fi->flags & LIBWIFI_FLAGS_IS_QOS) { + memset(&fh.data_qos, 0, sizeof(struct libwifi_data_qos_frame_header)); + memcpy(&fh.data_qos, frame_data, sizeof(struct libwifi_data_qos_frame_header)); + } else { + memset(&fh.data, 0, sizeof(struct libwifi_data_frame_header)); + memcpy(&fh.data, frame_data, sizeof(struct libwifi_data_frame_header)); + } + break; + case TYPE_MANAGEMENT: + if (frame_control->flags.ordered) { + header_len = sizeof(struct libwifi_mgmt_ordered_frame_header); + if (frame_data_len < header_len) { + free(frame_data); + return -EINVAL; + } + memcpy(&fh.mgmt_ordered, frame_data, header_len); + } else { + header_len = sizeof(struct libwifi_mgmt_unordered_frame_header); + if (frame_data_len < header_len) { + free(frame_data); + return -EINVAL; + } + memcpy(&fh.mgmt_unordered, frame_data, header_len); + } + break; + case TYPE_CONTROL: + header_len = sizeof(struct libwifi_ctrl_frame_header); + if (frame_data_len < header_len) { + free(frame_data); + return -EINVAL; + } + memcpy(&fh.ctrl, frame_data, sizeof(struct libwifi_ctrl_frame_header)); + break; + default: + free(frame_data); + return -EINVAL; + } + + fi->len = frame_data_len; + fi->header = fh; + fi->header_len = header_len; + memcpy(&fi->frame_control, frame_control, sizeof(struct libwifi_frame_ctrl)); + + fi->body = malloc(fi->len - fi->header_len); + memcpy(fi->body, frame_data + header_len, (fi->len - fi->header_len)); + + free(frame_data); + + return 0; +} + +void libwifi_free_wifi_frame(struct libwifi_frame *fi) { + free(fi->body); +} diff --git a/src/libwifi/core/frame/frame.h b/src/libwifi/core/frame/frame.h new file mode 100644 index 0000000..8c5c89f --- /dev/null +++ b/src/libwifi/core/frame/frame.h @@ -0,0 +1,334 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_FRAME_H +#define LIBWIFI_CORE_FRAME_H + +#include "../../core/misc/byteswap.h" + +#include +#include + +/* libwifi_frame Flags */ +#define LIBWIFI_FLAGS_FCS_PRESENT (1 << 0) +#define LIBWIFI_FLAGS_IS_QOS (1 << 1) + +/* Defined frame types and sub-types */ +enum libwifi_frame_type { + TYPE_MANAGEMENT = 0, + TYPE_CONTROL = 1, + TYPE_DATA = 2, + TYPE_EXTENSION = 3, +}; +enum libwifi_mgmt_subtypes { + SUBTYPE_ASSOC_REQ = 0, + SUBTYPE_ASSOC_RESP = 1, + SUBTYPE_REASSOC_REQ = 2, + SUBTYPE_REASSOC_RESP = 3, + SUBTYPE_PROBE_REQ = 4, + SUBTYPE_PROBE_RESP = 5, + SUBTYPE_TIME_ADV = 6, + // Reserved = 7, + SUBTYPE_BEACON = 8, + SUBTYPE_ATIM = 9, + SUBTYPE_DISASSOC = 10, + SUBTYPE_AUTH = 11, + SUBTYPE_DEAUTH = 12, + SUBTYPE_ACTION = 13, + SUBTYPE_ACTION_NOACK = 14, + // Reserved = 15, +}; +enum libwifi_control_subtypes { + // Reserved = 0-3, + SUBTYPE_TACK = 3, + SUBTYPE_BEAMFORM_REPORT_POLL = 4, + SUBTYPE_VHT_NDP_ANNOUNCE = 5, + SUBTYPE_CF_EXTENSION = 6, + SUBTYPE_WRAPPER = 7, + SUBTYPE_BLOCK_ACK_REQ = 8, + SUBTYPE_BLOCK_ACK = 9, + SUBTYPE_PS_POLL = 10, + SUBTYPE_RTS = 11, + SUBTYPE_CTS = 12, + SUBTYPE_ACK = 13, + SUBTYPE_CF_END = 14, + SUBTYPE_CF_END_CF_ACK = 15, +}; +enum libwifi_control_extension_subtypes { + // Reserved = 0-1, + SUBTYPE_CF_EXT_POLL = 2, + SUBTYPE_CF_EXT_SPR = 3, + SUBTYPE_CF_EXT_GRANT = 4, + SUBTYPE_CF_EXT_DMG_CTS = 5, + SUBTYPE_CF_EXT_DMG_DTS = 6, + SUBTYPE_CF_EXT_GRANT_ACK = 7, + SUBTYPE_CF_EXT_SSW = 8, + SUBTYPE_CF_EXT_SSW_FEEDBACK = 9, + SUBTYPE_CF_EXT_SSW_ACK = 10, + // Reserved = 11-15, +}; +enum libwifi_data_subtypes { + SUBTYPE_DATA = 0, + // Reserved = 1-3, + SUBTYPE_DATA_NULL = 4, + // Reserved = 4-7, + SUBTYPE_DATA_QOS_DATA = 8, + SUBTYPE_DATA_QOS_DATA_CF_ACK = 9, + SUBTYPE_DATA_QOS_DATA_CF_POLL = 10, + SUBTYPE_DATA_QOS_DATA_CF_ACK_CF_POLL = 11, + SUBTYPE_DATA_QOS_NULL = 12, + // Reserved = 13, + SUBTYPE_DATA_QOS_CF_POLL = 14, + SUBTYPE_DATA_QOS_CF_ACK_CF_POLL = 15, +}; +enum libwifi_extension_subtypes { + SUBTYPE_EXTENSION_DMG_BEACON = 0, + SUBTYPE_EXTENSION_SIG_BEACON = 1, + // Reserved = 2-15 +}; + +/* + * libwifi Representation of an 802.11 Frame Control Field's Flags. + */ + +struct libwifi_frame_ctrl_flags { + unsigned int to_ds : 1; + unsigned int from_ds : 1; + unsigned int more_frags : 1; + unsigned int retry : 1; + unsigned int power_mgmt : 1; + unsigned int more_data : 1; + unsigned int protect : 1; + unsigned int ordered : 1; +} __attribute__((packed)); + +/* + * libwifi Representation of an 802.11 Frame Control Field. + */ +struct libwifi_frame_ctrl { + unsigned int version : 2; + unsigned int type : 2; + unsigned int subtype : 4; + struct libwifi_frame_ctrl_flags flags; +} __attribute__((packed)); + +/* + * libwifi Representation of an 802.11 Sequence Control Field. + */ +struct libwifi_seq_control { + unsigned int fragment_number : 4; + unsigned int sequence_number : 12; +} __attribute__((packed)); + +/* + * libwifi Representation of an 802.11 Data QoS Control Field. + * + * As the bits of the QoS Control Field can vary depending on other + * factors, generic bit names are used here. + */ +struct libwifi_qos_control { + unsigned int bit1 : 1; + unsigned int bit2 : 1; + unsigned int bit3 : 1; + unsigned int bit4 : 1; + unsigned int bit5 : 1; + unsigned int bit6 : 1; + unsigned int bit7 : 1; + unsigned int bit8 : 1; + unsigned int bit9 : 1; + unsigned int bit10 : 1; + unsigned int bit11 : 1; + unsigned int bit12 : 1; + unsigned int bit13 : 1; + unsigned int bit14 : 1; + unsigned int bit15 : 1; + unsigned int bit16 : 1; +} __attribute__((packed)); + +/* + * libwifi Representation of an ordered Management Frame header. + * + * ┌───────────────────────────┐ + * │ Frame Control Field │ ── 2 Bytes + * ├───────────────────────────┤ + * │ Duration │ ── 2 Bytes + * ├───────────────────────────┤ + * │ Address 1 │ ── 6 Bytes + * ├───────────────────────────┤ + * │ Address 2 │ ── 6 Bytes + * ├───────────────────────────┤ + * │ Address 3 │ ── 6 Bytes + * ├───────────────────────────┤ + * │ Sequence Control │ ── 2 Bytes + * ├───────────────────────────┤ + * │ HT Control │ ── 4 Bytes + * └───────────────────────────┘ + */ +struct libwifi_mgmt_ordered_frame_header { + struct libwifi_frame_ctrl frame_control; + uint16_t duration; + unsigned char addr1[6]; + unsigned char addr2[6]; + unsigned char addr3[6]; + struct libwifi_seq_control seq_control; + uint32_t ht_control; +} __attribute__((packed)); + +/* + * libwifi Representation of an unordered Management Frame header. + * + * ┌───────────────────────────┐ + * │ Frame Control Field │ ── 2 Bytes + * ├───────────────────────────┤ + * │ Duration │ ── 2 Bytes + * ├───────────────────────────┤ + * │ Address 1 │ ── 6 Bytes + * ├───────────────────────────┤ + * │ Address 2 │ ── 6 Bytes + * ├───────────────────────────┤ + * │ Address 3 │ ── 6 Bytes + * ├───────────────────────────┤ + * │ Sequence Control │ ── 2 Bytes + * └───────────────────────────┘ + */ +struct libwifi_mgmt_unordered_frame_header { + struct libwifi_frame_ctrl frame_control; + uint16_t duration; + unsigned char addr1[6]; + unsigned char addr2[6]; + unsigned char addr3[6]; + struct libwifi_seq_control seq_control; +} __attribute__((packed)); + +/* + * libwifi Representation of a Control Frame header. + * + * ┌───────────────────────────┐ + * │ Frame Control Field │ ── 2 Bytes + * ├───────────────────────────┤ + * │ Duration │ ── 2 Bytes + * └───────────────────────────┘ + */ +struct libwifi_ctrl_frame_header { + struct libwifi_frame_ctrl frame_control; + uint16_t duration; +} __attribute__((packed)); + +/* + * libwifi Representation of a non-QoS Data Frame header. + * + * ┌───────────────────────────┐ + * │ Frame Control Field │ ── 2 Bytes + * ├───────────────────────────┤ + * │ Duration │ ── 2 Bytes + * ├───────────────────────────┤ + * │ Address 1 │ ── 6 Bytes + * ├───────────────────────────┤ + * │ Address 2 │ ── 6 Bytes + * ├───────────────────────────┤ + * │ Address 3 │ ── 6 Bytes + * ├───────────────────────────┤ + * │ Sequence Control │ ── 2 Bytes + * └───────────────────────────┘ + */ +struct libwifi_data_frame_header { + struct libwifi_frame_ctrl frame_control; + uint16_t duration; + unsigned char addr1[6]; + unsigned char addr2[6]; + unsigned char addr3[6]; + struct libwifi_seq_control seq_control; +} __attribute__((packed)); + +/* + * libwifi Representation of a QoS Data Frame header. + * + * ┌───────────────────────────┐ + * │ Frame Control Field │ ── 2 Bytes + * ├───────────────────────────┤ + * │ Duration │ ── 2 Bytes + * ├───────────────────────────┤ + * │ Address 1 │ ── 6 Bytes + * ├───────────────────────────┤ + * │ Address 2 │ ── 6 Bytes + * ├───────────────────────────┤ + * │ Address 3 │ ── 6 Bytes + * ├───────────────────────────┤ + * │ Sequence Control │ ── 2 Bytes + * ├───────────────────────────┤ + * │ QoS Control │ ── 2 Bytes + * └───────────────────────────┘ + */ +struct libwifi_data_qos_frame_header { + struct libwifi_frame_ctrl frame_control; + uint16_t duration; + unsigned char addr1[6]; + unsigned char addr2[6]; + unsigned char addr3[6]; + struct libwifi_seq_control seq_control; + struct libwifi_qos_control qos_control; +} __attribute__((packed)); + +/* + * Union of all frame type headers for use with a libwifi_frame struct + */ +union libwifi_frame_header { + struct libwifi_mgmt_ordered_frame_header mgmt_ordered; + struct libwifi_mgmt_unordered_frame_header mgmt_unordered; + struct libwifi_ctrl_frame_header ctrl; + struct libwifi_data_frame_header data; + struct libwifi_data_qos_frame_header data_qos; +}; + +/* + * Union of all Management Frame headers + */ +union libwifi_mgmt_frame_header { + struct libwifi_mgmt_ordered_frame_header ordered; + struct libwifi_mgmt_unordered_frame_header unordered; +}; + +/* + * A libwifi_frame struct is used to represent any type of 802.11 + * frame in libwifi. + */ +struct libwifi_frame { + uint16_t flags; + struct libwifi_frame_ctrl frame_control; + size_t len; + union libwifi_frame_header header; + size_t header_len; + unsigned char *body; +}; + +/** + * Convert a sniffed 802.11 frame into a libwifi_frame. + * + * @param fi A libwifi_frame struct + * @param frame An 802.11 frame + * @param frame_len Length of the sniffed 802.11 frame + * @return + */ +int libwifi_get_wifi_frame(struct libwifi_frame *fi, const unsigned char *frame, size_t frame_len, + int radiotap); + +/** + * Free any dynamically allocated data inside a libwifi_frame. + * + * @param fi A libwifi_frame struct + */ +void libwifi_free_wifi_frame(struct libwifi_frame *fi); + +#endif /* LIBWIFI_CORE_FRAME_H */ diff --git a/src/libwifi/core/frame/management/action.h b/src/libwifi/core/frame/management/action.h new file mode 100644 index 0000000..4bd78dd --- /dev/null +++ b/src/libwifi/core/frame/management/action.h @@ -0,0 +1,93 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_ACTIONS_H +#define LIBWIFI_CORE_ACTIONS_H + +#include "../frame.h" +#include + +/* Defined action fixed parameter values */ +enum libwifi_actions { + ACTION_SPECTRUM_MGMT = 0, + ACTION_QOS = 1, + // Reserved 2 + ACTION_BLOCK_ACK = 3, + ACTION_PUBLIC = 4, + ACTION_RADIO_MEASUREMENT = 5, + ACTION_FAST_BSS_TRANSITION = 6, + ACTION_HT = 7, + ACTION_SA_QUERY = 8, + ACTION_PROTECTED_DOPA = 9, + ACTION_WNM = 10, + ACTION_UNSUPPORTED_WNM = 11, + ACTION_TDLS = 12, + ACTION_MESH = 13, + ACTION_MULTIHOP = 14, + ACTION_SELF_PROTECTED = 15, + ACTION_DMG = 16, + // Reserved 17 + ACTION_FAST_SESSION_TRANSFER = 18, + ACTION_ROBUST_AV_STREAM = 19, + ACTION_UNPROTECTED_DMG = 20, + ACTION_VHT = 21, + ACTION_UNPROTECTED_SIG = 22, + ACTION_SIG = 23, + ACTION_FLOW_CONTROL = 24, + ACTION_CTRL_MCS_NEG = 25, + ACTION_FILS = 26, + ACTION_CDMG = 27, + ACTION_CMMG = 28, + ACTION_GLK = 29, + // Reserved 30-125 + ACTION_VENDOR_PROTECTED = 126, + ACTION_VENDOR = 127, + // Error 128-255 +}; + +/** + * Action Layout + * ───────────────────────────────────── + * ┌─────────────────────────────────────┐ + * │ Header │ Bytes: 24 + * ├─────────────────────────────────────┤ + * │ Fixed Parameters │ Bytes: Variable + * │┌───────────────────────────────────┐│ + * ││ category ││ Bytes: 1 + * │├───────────────────────────────────┤│ + * ││ detail ││ Bytes: Variable + * ││┌─────────────────────────────────┐││ + * │││ tagged parameters │││ + * ││└─────────────────────────────────┘││ + * │└───────────────────────────────────┘│ + * └─────────────────────────────────────┘ + */ + +struct libwifi_action_detail { + uint8_t detail_length; + char *detail; +} __attribute__((packed)); + +struct libwifi_action_fixed_parameters { + uint8_t category; + struct libwifi_action_detail details; +} __attribute__((packed)); + +struct libwifi_action { + struct libwifi_mgmt_unordered_frame_header frame_header; + struct libwifi_action_fixed_parameters fixed_parameters; +} __attribute__((packed)); + +#endif /* LIBWIFI_CORE_ACTIONS_H */ diff --git a/src/libwifi/core/frame/management/assoc_request.h b/src/libwifi/core/frame/management/assoc_request.h new file mode 100644 index 0000000..5a35762 --- /dev/null +++ b/src/libwifi/core/frame/management/assoc_request.h @@ -0,0 +1,51 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_ASSOCREQ_H +#define LIBWIFI_CORE_ASSOCREQ_H + +#include "../frame.h" +#include "../tag.h" +#include + +/** + * Association Request Layout + * ───────────────────────────────── + * ┌─────────────────────────────────┐ + * │ Header │ Bytes: 24 + * ├─────────────────────────────────┤ + * │ Fixed Parameters │ Bytes: 4 + * │┌───────────────────────────────┐│ + * ││ capabilities ││ Bytes: 2 + * │├───────────────────────────────┤│ + * ││ listen interval ││ Bytes: 2 + * │└───────────────────────────────┘│ + * ├─────────────────────────────────┤ + * │ Tagged Parameters │ Bytes: Variable + * └─────────────────────────────────┘ + */ + +struct libwifi_assoc_req_fixed_parameters { + uint16_t capabilities_information; + uint16_t listen_interval; +} __attribute__((packed)); + +struct libwifi_assoc_req { + struct libwifi_mgmt_unordered_frame_header frame_header; + struct libwifi_assoc_req_fixed_parameters fixed_parameters; + struct libwifi_tagged_parameters tags; +} __attribute__((packed)); + +#endif /* LIBWIFI_CORE_ASSOCREQ_H */ diff --git a/src/libwifi/core/frame/management/assoc_response.h b/src/libwifi/core/frame/management/assoc_response.h new file mode 100644 index 0000000..85f5328 --- /dev/null +++ b/src/libwifi/core/frame/management/assoc_response.h @@ -0,0 +1,54 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_ASSOCRESP_H +#define LIBWIFI_CORE_ASSOCRESP_H + +#include "../frame.h" +#include "../tag.h" +#include + +/** + * Association Response Layout + * ───────────────────────────────── + * ┌─────────────────────────────────┐ + * │ Header │ Bytes: 24 + * ├─────────────────────────────────┤ + * │ Fixed Parameters │ Bytes: 6 + * │┌───────────────────────────────┐│ + * ││ capabilities ││ Bytes: 2 + * │├───────────────────────────────┤│ + * ││ status ││ Bytes: 2 + * │├───────────────────────────────┤│ + * ││ association id ││ Bytes: 2 + * │└───────────────────────────────┘│ + * ├─────────────────────────────────┤ + * │ Tagged Parameters │ Bytes: Variable + * └─────────────────────────────────┘ + */ + +struct libwifi_assoc_resp_fixed_parameters { + uint16_t capabilities_information; + uint16_t status_code; + uint16_t association_id; +} __attribute__((packed)); + +struct libwifi_assoc_resp { + struct libwifi_mgmt_unordered_frame_header frame_header; + struct libwifi_assoc_resp_fixed_parameters fixed_parameters; + struct libwifi_tagged_parameters tags; +} __attribute__((packed)); + +#endif /* LIBWIFI_CORE_ASSOCRESP_H */ diff --git a/src/libwifi/core/frame/management/atim.h b/src/libwifi/core/frame/management/atim.h new file mode 100644 index 0000000..18a01e2 --- /dev/null +++ b/src/libwifi/core/frame/management/atim.h @@ -0,0 +1,33 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_ATIM_H +#define LIBWIFI_CORE_ATIM_H + +#include "../frame.h" + +/** + * ATIM Frame Layout + * ───────────────────────────────── + * ┌─────────────────────────────────┐ + * │ Header │ Bytes: 24 + * └─────────────────────────────────┘ + */ + +struct libwifi_atim { + struct libwifi_mgmt_unordered_frame_header frame_header; +}; + +#endif /* LIBWIFI_CORE_ATIM_H */ diff --git a/src/libwifi/core/frame/management/authentication.h b/src/libwifi/core/frame/management/authentication.h new file mode 100644 index 0000000..c7707c6 --- /dev/null +++ b/src/libwifi/core/frame/management/authentication.h @@ -0,0 +1,54 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_AUTH_H +#define LIBWIFI_CORE_AUTH_H + +#include "../frame.h" +#include "../tag.h" +#include + +/** + * Authentication Layout + * ───────────────────────────────── + * ┌─────────────────────────────────┐ + * │ Header │ Bytes: 24 + * ├─────────────────────────────────┤ + * │ Fixed Parameters │ Bytes: 6 + * │┌───────────────────────────────┐│ + * ││ algorithm ││ Bytes: 2 + * │├───────────────────────────────┤│ + * ││ transaction ││ Bytes: 2 + * │├───────────────────────────────┤│ + * ││ status ││ Bytes: 2 + * │└───────────────────────────────┘│ + * ├─────────────────────────────────┤ + * │ Tagged Parameters │ Bytes: Variable + * └─────────────────────────────────┘ + */ + +struct libwifi_auth_fixed_parameters { + uint16_t algorithm_number; + uint16_t transaction_sequence; + uint16_t status_code; +} __attribute__((packed)); + +struct libwifi_auth { + struct libwifi_mgmt_unordered_frame_header frame_header; + struct libwifi_auth_fixed_parameters fixed_parameters; + struct libwifi_tagged_parameters tags; +} __attribute__((packed)); + +#endif /* LIBWIFI_CORE_AUTH_H */ diff --git a/src/libwifi/core/frame/management/beacon.h b/src/libwifi/core/frame/management/beacon.h new file mode 100644 index 0000000..f5c4d72 --- /dev/null +++ b/src/libwifi/core/frame/management/beacon.h @@ -0,0 +1,54 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_BEACON_H +#define LIBWIFI_CORE_BEACON_H + +#include "../frame.h" +#include "../tag.h" +#include + +/** + * Beacon Layout + * ────────────────────────────── + * ┌──────────────────────────────┐ + * │ Header │ Bytes: 24 + * ├──────────────────────────────┤ + * │ Fixed Parameters │ Bytes: 12 + * │┌────────────────────────────┐│ + * ││ timestamp ││ Bytes: 4 + * │├────────────────────────────┤│ + * ││ interval ││ Bytes: 2 + * │├────────────────────────────┤│ + * ││ capabilities ││ Bytes: 2 + * │└────────────────────────────┘│ + * ├──────────────────────────────┤ + * │ Tagged Parameters │ Bytes: Variable + * └──────────────────────────────┘ + */ + +struct libwifi_beacon_fixed_parameters { + uint64_t timestamp; + uint16_t beacon_interval; + uint16_t capabilities_information; +} __attribute__((packed)); + +struct libwifi_beacon { + struct libwifi_mgmt_unordered_frame_header frame_header; + struct libwifi_beacon_fixed_parameters fixed_parameters; + struct libwifi_tagged_parameters tags; +} __attribute__((packed)); + +#endif /* LIBWIFI_CORE_BEACON_H */ diff --git a/src/libwifi/core/frame/management/common.h b/src/libwifi/core/frame/management/common.h new file mode 100644 index 0000000..1f5d042 --- /dev/null +++ b/src/libwifi/core/frame/management/common.h @@ -0,0 +1,101 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_COMMON_H +#define LIBWIFI_CORE_COMMON_H + +#include "../../misc/security.h" +#include "../tag.h" +#include +#include + +#define LIBWIFI_BSS 0 +#define LIBWIFI_STA 1 + +/* + * A libwifi_bss struct is used as a common model for BSS / APs, and can be derived + * from parsed frames or used to generate new frames. Fields may be optional. + * + * transmitter - The transmitter MAC address + * receiver - The receiver MAC address + * bssid - BSSID MAC address + * ssid - AP SSID + * hidden - Hidden state boolean + * channel - BSS Channel + * wps - WPS state boolean + * encryption_info - Bitfield of encryption state, such as WPA version and ciphers + * signal - RSSI in dBm + * wpa_info - WPA1 information, present if encryption_info has the WPA1 bit set + * rsn_info - WPA2 and/or WPA3 information, present if encryption_info has WPA2 or WPA3 bit set + * tags - List of tagged parameters + */ +struct libwifi_bss { + unsigned char transmitter[6]; + unsigned char receiver[6]; + unsigned char bssid[6]; + char ssid[33]; + int8_t hidden; + uint8_t channel; + uint8_t wps; + uint64_t encryption_info; + int signal; + struct libwifi_wpa_info wpa_info; + struct libwifi_rsn_info rsn_info; + struct libwifi_tagged_parameters tags; +}; + +/* + * A libwifi_bss can be populated with dynamically allocated tags, which must be free'd by + * the user application to avoid memory leaks. This function provides an easy wrapper for any + * libwifi allocations made. + */ +static inline void libwifi_free_bss(struct libwifi_bss *bss) { + free(bss->tags.parameters); +} + +/* + * A libwifi_sta struct is used as a common model for stations, roaming or associated, + * and can be derived from parsed frames or used to generate new frames. Fields may be optional. + * + * channel - BSS Channel + * randomized - Client has a likely randomized MAC + * transmitter - The transmitter MAC address + * receiver - The receiver MAC address + * bssid - BSSID MAC address + * ssid - AP SSID + * broadcast_ssid - STA is broadcasting for SSID + * tags - List of tagged parameters + */ +struct libwifi_sta { + uint8_t channel; + uint8_t randomized; + unsigned char transmitter[6]; + unsigned char receiver[6]; + unsigned char bssid[6]; + char ssid[33]; + uint8_t broadcast_ssid; + struct libwifi_tagged_parameters tags; +}; + +/* + * A libwifi_sta can be populated with dynamically allocated tags, which must be free'd by + * the user application to avoid memory leaks. This function provides an easy wrapper for any + * libwifi allocations made. + */ +static inline void libwifi_free_sta(struct libwifi_sta *sta) { + free(sta->tags.parameters); +} + +#endif /* LIBWIFI_CORE_COMMON_H */ diff --git a/src/libwifi/core/frame/management/deauthentication.h b/src/libwifi/core/frame/management/deauthentication.h new file mode 100644 index 0000000..a01de7c --- /dev/null +++ b/src/libwifi/core/frame/management/deauthentication.h @@ -0,0 +1,55 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_DEAUTH_H +#define LIBWIFI_CORE_DEAUTH_H + +#include "../frame.h" +#include "../tag.h" +#include + +/** + * Deauthentication Layout + * ────────────────────────── + * ┌──────────────────────────┐ + * │ Header │ Bytes: 24 + * ├──────────────────────────┤ + * │ Fixed Parameters │ Bytes: 2 + * │┌────────────────────────┐│ + * ││ reason code ││ Bytes: 2 + * │└────────────────────────┘│ + * ├──────────────────────────┤ + * │ Tagged Parameters │ Bytes: Variable + * └──────────────────────────┘ + */ + +struct libwifi_deauth_fixed_parameters { + uint16_t reason_code; +} __attribute__((packed)); + +struct libwifi_deauth { + struct libwifi_mgmt_unordered_frame_header frame_header; + struct libwifi_deauth_fixed_parameters fixed_parameters; + struct libwifi_tagged_parameters tags; +} __attribute__((packed)); + +struct libwifi_parsed_deauth { + int ordered; + union libwifi_mgmt_frame_header frame_header; + struct libwifi_deauth_fixed_parameters fixed_parameters; + struct libwifi_tagged_parameters tags; +} __attribute__((packed)); + +#endif /* LIBWIFI_CORE_DEAUTH_H */ diff --git a/src/libwifi/core/frame/management/disassociation.h b/src/libwifi/core/frame/management/disassociation.h new file mode 100644 index 0000000..ec6752a --- /dev/null +++ b/src/libwifi/core/frame/management/disassociation.h @@ -0,0 +1,55 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_DISASSOC_H +#define LIBWIFI_CORE_DISASSOC_H + +#include "../frame.h" +#include "../tag.h" +#include + +/** + * Disassociation Layout + * ────────────────────────── + * ┌──────────────────────────┐ + * │ Header │ Bytes: 24 + * ├──────────────────────────┤ + * │ Fixed Parameters │ Bytes: 2 + * │┌────────────────────────┐│ + * ││ reason code ││ Bytes: 2 + * │└────────────────────────┘│ + * ├──────────────────────────┤ + * │ Tagged Parameters │ Bytes: Variable + * └──────────────────────────┘ + */ + +struct libwifi_disassoc_fixed_parameters { + uint16_t reason_code; +} __attribute__((packed)); + +struct libwifi_disassoc { + struct libwifi_mgmt_unordered_frame_header frame_header; + struct libwifi_disassoc_fixed_parameters fixed_parameters; + struct libwifi_tagged_parameters tags; +} __attribute__((packed)); + +struct libwifi_parsed_disassoc { + int ordered; + union libwifi_mgmt_frame_header frame_header; + struct libwifi_disassoc_fixed_parameters fixed_parameters; + struct libwifi_tagged_parameters tags; +} __attribute__((packed)); + +#endif /* LIBWIFI_CORE_DISASSOC_H */ diff --git a/src/libwifi/core/frame/management/probe_request.h b/src/libwifi/core/frame/management/probe_request.h new file mode 100644 index 0000000..c54cafa --- /dev/null +++ b/src/libwifi/core/frame/management/probe_request.h @@ -0,0 +1,38 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_PROBEREQ_H +#define LIBWIFI_CORE_PROBEREQ_H + +#include "../frame.h" +#include "../tag.h" +#include + +/** + * Probe Request Layout + * ────────────────────────── + * ┌──────────────────────────┐ + * │ Header │ Bytes: 24 + * ├──────────────────────────┤ + * │ Tagged Parameters │ Bytes: Variable + * └──────────────────────────┘ + */ + +struct libwifi_probe_req { + struct libwifi_mgmt_unordered_frame_header frame_header; + struct libwifi_tagged_parameters tags; +} __attribute__((packed)); + +#endif /* LIBWIFI_CORE_PROBEREQ_H */ diff --git a/src/libwifi/core/frame/management/probe_response.h b/src/libwifi/core/frame/management/probe_response.h new file mode 100644 index 0000000..f89ae6f --- /dev/null +++ b/src/libwifi/core/frame/management/probe_response.h @@ -0,0 +1,54 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_PROBERESP_H +#define LIBWIFI_CORE_PROBERESP_H + +#include "../frame.h" +#include "../tag.h" +#include + +/** + * Probe Response Layout + * ────────────────────────────── + * ┌──────────────────────────────┐ + * │ Header │ Bytes: 24 + * ├──────────────────────────────┤ + * │ Fixed Parameters │ Bytes: 12 + * │┌────────────────────────────┐│ + * ││ timestamp ││ Bytes: 4 + * │├────────────────────────────┤│ + * ││ interval ││ Bytes: 2 + * │├────────────────────────────┤│ + * ││ capabilities ││ Bytes: 2 + * │└────────────────────────────┘│ + * ├──────────────────────────────┤ + * │ Tagged Parameters │ Bytes: Variable + * └──────────────────────────────┘ + */ + +struct libwifi_probe_resp_fixed_parameters { + uint64_t timestamp; + uint16_t probe_resp_interval; + uint16_t capabilities_information; +} __attribute__((packed)); + +struct libwifi_probe_resp { + struct libwifi_mgmt_unordered_frame_header frame_header; + struct libwifi_probe_resp_fixed_parameters fixed_parameters; + struct libwifi_tagged_parameters tags; +} __attribute__((packed)); + +#endif /* LIBWIFI_CORE_PROBERESP_H */ diff --git a/src/libwifi/core/frame/management/reassoc_request.h b/src/libwifi/core/frame/management/reassoc_request.h new file mode 100644 index 0000000..fe5784c --- /dev/null +++ b/src/libwifi/core/frame/management/reassoc_request.h @@ -0,0 +1,54 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_REASSOCREQ_H +#define LIBWIFI_CORE_REASSOCREQ_H + +#include "../frame.h" +#include "../tag.h" +#include + +/** + * Reassociation Request Layout + * ─────────────────────────────── + * ┌───────────────────────────────┐ + * │ Header │ Bytes: 24 + * ├───────────────────────────────┤ + * │ Fixed Parameters │ Bytes: 10 + * │┌─────────────────────────────┐│ + * ││ capabilities ││ Bytes: 2 + * │├─────────────────────────────┤│ + * ││ interval ││ Bytes: 2 + * │├─────────────────────────────┤│ + * ││ current AP address ││ Bytes: 6 + * │└─────────────────────────────┘│ + * ├───────────────────────────────┤ + * │ Tagged Parameters │ Bytes: Variable + * └───────────────────────────────┘ + */ + +struct libwifi_reassoc_req_fixed_parameters { + uint16_t capabilities_information; + uint16_t listen_interval; + unsigned char current_ap_address[6]; +} __attribute__((packed)); + +struct libwifi_reassoc_req { + struct libwifi_mgmt_unordered_frame_header frame_header; + struct libwifi_reassoc_req_fixed_parameters fixed_parameters; + struct libwifi_tagged_parameters tags; +} __attribute__((packed)); + +#endif /* LIBWIFI_CORE_REASSOCREQ_H */ diff --git a/src/libwifi/core/frame/management/reassoc_response.h b/src/libwifi/core/frame/management/reassoc_response.h new file mode 100644 index 0000000..c0b7f62 --- /dev/null +++ b/src/libwifi/core/frame/management/reassoc_response.h @@ -0,0 +1,54 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_REASSOCRESP_H +#define LIBWIFI_CORE_REASSOCRESP_H + +#include "../frame.h" +#include "../tag.h" +#include + +/** + * Reassociation Response Layout + * ────────────────────────────────── + * ┌──────────────────────────────────┐ + * │ Header │ Bytes: 24 + * ├──────────────────────────────────┤ + * │ Fixed Parameters │ Bytes: 6 + * │┌────────────────────────────────┐│ + * ││ capabilities ││ Bytes: 2 + * │├────────────────────────────────┤│ + * ││ status ││ Bytes: 2 + * │├────────────────────────────────┤│ + * ││ association id ││ Bytes: 2 + * │└────────────────────────────────┘│ + * ├──────────────────────────────────┤ + * │ Tagged Parameters │ Bytes: Variable + * └──────────────────────────────────┘ + */ + +struct libwifi_reassoc_resp_fixed_parameters { + uint16_t capabilities_information; + uint16_t status_code; + uint16_t association_id; +} __attribute__((packed)); + +struct libwifi_reassoc_resp { + struct libwifi_mgmt_unordered_frame_header frame_header; + struct libwifi_reassoc_resp_fixed_parameters fixed_parameters; + struct libwifi_tagged_parameters tags; +} __attribute__((packed)); + +#endif /* LIBWIFI_CORE_REASSOCRESP_H */ diff --git a/src/libwifi/core/frame/management/timing_ad.h b/src/libwifi/core/frame/management/timing_ad.h new file mode 100644 index 0000000..d0a8ac3 --- /dev/null +++ b/src/libwifi/core/frame/management/timing_ad.h @@ -0,0 +1,82 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_TIMINGAD_H +#define LIBWIFI_CORE_TIMINGAD_H + +#include +#include "../frame.h" +#include "../tag.h" + +/** + * Timing Advertisement Layout + * ────────────────────────────────── + * ┌──────────────────────────────────┐ + * │ Header │ Bytes: 24 + * ├──────────────────────────────────┤ + * │ Fixed Parameters │ Bytes: 6 + * │┌────────────────────────────────┐│ + * ││ timestamp ││ Bytes: 8 + * │├────────────────────────────────┤│ + * ││ measurement pilot interval ││ Bytes: 1 + * │├────────────────────────────────┤│ + * ││ beacon interval ││ Bytes: 2 + * │├────────────────────────────────┤│ + * ││ capabilities information ││ Bytes: 2 + * │├────────────────────────────────┤│ + * ││ country code ││ Bytes: 3 + * │├────────────────────────────────┤│ + * ││ maxmimum regulatory power ││ Bytes: 2 + * │├────────────────────────────────┤│ + * ││ maximum transmit power ││ Bytes: 1 + * │├────────────────────────────────┤│ + * ││ transmit power used ││ Bytes: 1 + * │├────────────────────────────────┤│ + * ││ noise floor ││ Bytes: 1 + * │└────────────────────────────────┘│ + * ├──────────────────────────────────┤ + * │ Tagged Parameters │ Bytes: Variable + * │┌────────────────────────────────┐│ + * ││ timing advert fields ││ Bytes: 17 + * │└────────────────────────────────┘│ + * └──────────────────────────────────┘ + */ + +struct libwifi_timing_advert_fields { + uint8_t timing_capabilities; + unsigned char time_value[10]; + unsigned char time_error[5]; + unsigned char time_update[1]; +} __attribute__((packed)); + +struct libwifi_timing_advert_fixed_params { + uint64_t timestamp; + uint8_t measurement_pilot_interval; + uint16_t beacon_interval; + uint16_t capabilities_information; + char country[3]; + uint16_t max_reg_power; + uint8_t max_tx_power; + uint8_t tx_power_used; + uint8_t noise_floor; +} __attribute__((packed)); + +struct libwifi_timing_advert { + struct libwifi_mgmt_unordered_frame_header frame_header; + struct libwifi_timing_advert_fixed_params fixed_parameters; + struct libwifi_tagged_parameters tags; +} __attribute__((packed)); + +#endif /* LIBWIFI_CORE_TIMINGAD_H */ diff --git a/src/libwifi/core/frame/tag.c b/src/libwifi/core/frame/tag.c new file mode 100644 index 0000000..9dec547 --- /dev/null +++ b/src/libwifi/core/frame/tag.c @@ -0,0 +1,131 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "tag.h" +#include "tag_iterator.h" + +#include +#include +#include +#include +#include + +int libwifi_add_tag(struct libwifi_tagged_parameters *tags, struct libwifi_tagged_parameter *tag) { + // Calculate the total length of the new tag + size_t parameter_len = sizeof(struct libwifi_tag_header) + tag->header.tag_len; + + // Initalise the supplied tagged parameters list, if not already done. + // Otherwise, extend the allocation to fit the new tag. + if (tags->length == 0) { + tags->parameters = malloc(parameter_len); + if (tags->parameters == NULL) { + return -ENOMEM; + } + } else { + void *buf = realloc(tags->parameters, tags->length + parameter_len); + if (buf == NULL) { + return -ENOMEM; + } + tags->parameters = buf; + } + + // Append the new tag to the list + memcpy(tags->parameters + tags->length, &tag->header, sizeof(struct libwifi_tag_header)); + memcpy(tags->parameters + tags->length + sizeof(struct libwifi_tag_header), tag->body, + tag->header.tag_len); + + // Update total tagged parameters length + tags->length += parameter_len; + + return 0; +} + +int libwifi_remove_tag(struct libwifi_tagged_parameters *tags, int tag_number) { + // Initalise a tag iterator + struct libwifi_tag_iterator it = {0}; + if (libwifi_tag_iterator_init(&it, tags->parameters, tags->length) != 0) { + return -EINVAL; + } + + // Loop through the tagged parameters list until landing on the supplied tag number + do { + if (it.tag_header->tag_num == tag_number) { + // Calculate the length of the tag we're removing, so that we know + // how many bytes to shrink the tagged parameter list by + size_t copy_len = tags->length - + (it.tag_data - tags->parameters) - + (it.tag_header->tag_len + sizeof(struct libwifi_tag_header)); + memcpy(tags->parameters, it.tag_data + it.tag_header->tag_len, copy_len); + size_t new_len = tags->length - it.tag_header->tag_len - sizeof(struct libwifi_tag_header); + tags->parameters = realloc(tags->parameters, new_len); + tags->length = new_len; + break; + } + } while (libwifi_tag_iterator_next(&it) != -1); + + return 0; +} + +size_t libwifi_create_tag(struct libwifi_tagged_parameter *tagged_parameter, int tag_number, + const unsigned char *tag_data, size_t tag_length) { + // Initalise the supplied tagged parameter struct + memset(tagged_parameter, 0, sizeof(struct libwifi_tagged_parameter)); + tagged_parameter->header.tag_len = tag_length; + tagged_parameter->header.tag_num = tag_number; + tagged_parameter->body = malloc(tag_length); + if (tagged_parameter->body == NULL) { + return -ENOMEM; + } + memset(tagged_parameter->body, 0, tag_length); + + // Copy the supplied data into the new tag body + memcpy(tagged_parameter->body, tag_data, tag_length); + + return sizeof(struct libwifi_tag_header) + tag_length; +} + +void libwifi_free_tag(struct libwifi_tagged_parameter *tagged_parameter) { + free(tagged_parameter->body); +} + +size_t libwifi_dump_tag(struct libwifi_tagged_parameter *tag, unsigned char *buf, size_t buf_len) { + if (tag->header.tag_len > buf_len) { + return -EINVAL; + } + + size_t offset = 0; + + memcpy(buf, &tag->header, sizeof(struct libwifi_tag_header)); + offset += sizeof(struct libwifi_tag_header); + memcpy(buf + offset, tag->body, tag->header.tag_len); + offset += tag->header.tag_len; + + return sizeof(struct libwifi_tag_header) + tag->header.tag_len; +} + +int libwifi_quick_add_tag(struct libwifi_tagged_parameters *tags, int tag_number, + const unsigned char *tag_data, size_t tag_length) { + struct libwifi_tagged_parameter tagged_parameter = {0}; + + size_t ret = libwifi_create_tag(&tagged_parameter, tag_number, tag_data, tag_length); + if (ret <= 0) { + return ret; + } + + libwifi_add_tag(tags, &tagged_parameter); + libwifi_free_tag(&tagged_parameter); + + return 0; +} diff --git a/src/libwifi/core/frame/tag.h b/src/libwifi/core/frame/tag.h new file mode 100644 index 0000000..02928fe --- /dev/null +++ b/src/libwifi/core/frame/tag.h @@ -0,0 +1,306 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_TAG_H +#define LIBWIFI_CORE_TAG_H + +#include +#include + +/* 802.11 Tagged Parameter values */ +enum libwifi_tag_numbers { + TAG_SSID = 0, + TAG_SUPP_RATES = 1, + // Reserved 2 + TAG_DS_PARAMETER = 3, + TAG_CF_PARAMETER = 4, + TAG_TIM = 5, + TAG_BSS_PARAMETERS = 6, + TAG_COUNTRY = 7, + // Reserved 8-9 + TAG_REQUEST = 10, + TAG_BSS_LOAD = 11, + TAG_EDCA_PARAMETERS = 12, + TAG_TSPEC = 13, + TAG_TCLAS = 14, + TAG_SCHEDULE = 15, + TAG_CHALLENGE_TEXT = 16, + // Reserved 17-31 + TAG_POWER_CONSTRAINT = 32, + TAG_POWER_CAPABILITY = 33, + TAG_TPC_REQUEST = 34, + TAG_TPC_REPORT = 35, + TAG_SUPPORTED_CHANNELS = 36, + TAG_CHANNEL_SWITCH_ANNOUNCEMENT = 37, + TAG_MEASUREMENT_REQUEST = 38, + TAG_MEASUREMENT_REPORT = 39, + TAG_QUIET = 40, + TAG_IBSS_DFS = 41, + TAG_ERP = 42, + TAG_TS_DELAY = 43, + TAG_TCLAS_PROCESSING = 44, + TAG_HT_CAPABILITIES = 45, + TAG_QOS_CAPABILITY = 46, + // Reserved 47 + TAG_RSN = 48, + // Reserved 49 + TAG_EXTENDED_SUPPORTED_RATES = 50, + TAG_AP_CHANNEL_REPORT = 51, + TAG_NEIGHBOR_REPORT = 52, + TAG_RCPI = 53, + TAG_MOBILITY_DOMAIN = 54, + TAG_FAST_BSS_TRANSITION = 55, + TAG_TIMEOUT_INTERVAL = 56, + TAG_RIC_DATA = 57, + TAG_DSE_REGISTERED_LOCATION = 58, + TAG_SUPPORTED_OPERATING_CLASSES = 59, + TAG_EXTENDED_CHANNEL_SWITCH_ANNOUNCEMENT = 60, + TAG_HT_OPERATION = 61, + TAG_SECONDARY_CHANNEL_OFFSET = 62, + TAG_BSS_AVERAGE_ACCESS_DELAY = 63, + TAG_ANTENNA = 64, + TAG_RSNI = 65, + TAG_MEASUREMENT_PILOT_TRANSMISSION = 66, + TAG_BSS_AVAILABLE_ADMISSION_CAPACITY = 67, + TAG_BSS_AC_ACCESS_DELAY = 68, + TAG_TIME_ADVERTISEMENT = 69, + TAG_RM_ENABLED_CAPABILITIES = 70, + TAG_MULTIPLE_BSSID = 71, + TAG_BSS_COEXISTENCE = 72, + TAG_BSS_INTOLERANT_CHANNEL_REPORT = 73, + TAG_OVERLAPPING_BSS_PARAMETERS = 74, + TAG_RIC_DESCRIPTOR = 75, + TAG_MANAGEMENT_MIC = 76, + // Undefined 77 + TAG_EVENT_REQUEST = 78, + TAG_EVENT_REPORT = 79, + TAG_DIAGNOSTIC_REQUEST = 80, + TAG_DIAGNOSTIC_REPORT = 81, + TAG_LOCATION_PARAMTERS = 82, + TAG_NONTRANSMITTED_BSSID_CAPABILITY = 83, + TAG_SSID_LIST = 84, + TAG_MULTIPLE_BSSID_INDEX = 85, + TAG_FMS_DESCRIPTOR = 86, + TAG_FMS_REQUEST = 87, + TAG_FMS_RESPONSE = 88, + TAG_QOS_TRAFFIC_CAPABILITY = 89, + TAG_BSS_MAX_IDLE_PERIOD = 90, + TAG_TFS_REQUEST = 91, + TAG_TFS_RESPONSE = 92, + TAG_WNM_SLEEP_MODE = 93, + TAG_TIM_BROADCAST_REQUEST = 94, + TAG_TIM_BROADCAST_RESPONSE = 95, + TAG_COLLOCATED_INTERFERENCE_REPORT = 96, + TAG_CHANNEL_USAGE = 97, + TAG_TIME_ZONE = 98, + TAG_DMS_REQUEST = 99, + TAG_DMS_RESPONSE = 100, + TAG_LINK_IDENTIFIER = 101, + TAG_WAKEUP_SCHEDULE = 102, + // Undefined 103 + TAG_CHANNEL_SWITCH_TIMING = 104, + TAG_PTI_CONTROL = 105, + TAG_TPU_BUFFER_STATUS = 106, + TAG_INTERWORKING = 107, + TAG_ADVERTISEMENT_PROTOCOL = 108, + TAG_EXPEDITED_BANDWIDTH_REQUEST = 109, + TAG_QOS_MAP = 110, + TAG_ROAMING_CONSORTIUM = 111, + TAG_EMERGENCY_ALERT_IDENTIFIER = 112, + TAG_MESH_CONFIGURATION = 113, + TAG_MESH_ID = 114, + TAG_MESH_LINK_METRIC_REPORT = 115, + TAG_CONGESTION_NOTIFICATION = 116, + TAG_MESH_PEERING_MANAGEMENT = 117, + TAG_MESH_CHANNEL_SWITCH_PARAMETERS = 118, + TAG_MESH_AWAKE_WINDOW = 119, + TAG_BEACON_TIMING = 120, + TAG_MCCAOP_SETUP_REQUEST = 121, + TAG_MCCAOP_SETUP_REPLY = 122, + TAG_MCCAOP_ADVERTISEMENT = 123, + TAG_MCCAOP_TEARDOWN = 124, + TAG_GANN = 125, + TAG_RANN = 126, + TAG_EXTENDED_CAPABILITIES = 127, + // Reserved 128-129 + TAG_PREQ = 130, + TAG_PREP = 131, + TAG_PERR = 132, + // Reserved 133-136 + TAG_PXU = 137, + TAG_PXUC = 138, + TAG_AUTHENTICATED_MESH_PEERING_EXCHANGE = 139, + TAG_MIC = 140, + TAG_DESTINATION_URI = 141, + TAG_U_APSD_COEXISTENCE = 142, + TAG_DMG_WAKEUP_SCHEDULE = 143, + TAG_EXTENDED_SCHEDULE = 144, + TAG_STA_AVAILABILITY = 145, + TAG_DMG_TSPEC = 146, + TAG_NEXT_DMG_ATI = 147, + // Reserved 149-150 + TAG_DMG_OPERATION = 151, + TAG_DMG_BSS_PARAMETER_CHANGE = 152, + TAG_DMG_BEAM_REFINEMENT = 153, + TAG_CHANNEL_MEASUREMENT_FEEDBACK = 154, + // Reserved 155-156 + TAG_AWAKE_WINDOW = 157, + TAG_MULTI_BAND = 158, + TAG_ADDBA_EXTENSION = 159, + TAG_NEXTPCP_LIST = 160, + TAG_PCP_HANDOVER = 161, + TAG_DMG_LINK_MARGIN = 162, + TAG_SWITCHING_STREAM = 163, + TAG_SESSION_TRANSITION = 164, + TAG_DYNAMIC_TONE_PAIRING_REPORT = 165, + TAG_CLUSTER_REPORT = 166, + TAG_RELAY_CAPABILITIES = 167, + TAG_RELAY_TRANSFER_PARAMETER_SET = 168, + TAG_BEAMLINK_MAINTENANCE = 169, + TAG_MULTIPLE_MAC_SUBLAYERS = 170, + TAG_U_PID = 171, + TAG_DMG_LINK_ADAPTATION_ACKNOWLEDGEMENT = 172, + // Reserved 173 + TAG_MCCAOP_ADVERTISEMENT_OVERVIEW = 174, + TAG_QUIET_PERIOD_REQUEST = 175, + // Reserved 176 + TAG_QUIET_PERIOD_RESPONSE = 177, + // Reserved 178-180 + TAG_QMF_POLICY = 181, + TAG_ECAPC_POLICY = 182, + TAG_CLUSTER_TIME_OFFSET = 183, + TAG_INTRA_ACCESS_CATEGORY_PRIORITY = 184, + TAG_SCS_DESCRIPTOR = 185, + TAG_QLOAD_REPORT = 186, + TAG_HCCA_TXOP_UPDATE_COUNT = 187, + TAG_HIGHER_LAYER_STREAM_ID = 188, + TAG_GCR_GROUP_ADDRESS = 189, + TAG_ANTENNA_SECTOR_ID_PATTERN = 190, + TAG_VHT_CAPABILITIES = 191, + TAG_VHT_OPERATION = 192, + TAG_EXTENDED_BSS_LOAD = 193, + TAG_WIDE_BANDWIDTH_CHANNEL_SWITCH = 194, + TAG_TRANSMIT_POWER_ENVELOPE = 195, + TAG_CHANNEL_SWITCH_WRAPPER = 196, + TAG_AID = 197, + TAG_QUIET_CHANNEL = 198, + TAG_UPSIM = 200, + TAG_REDUCED_NEIGHBOR_REPORT = 201, + TAG_TVHT_OPERATION = 202, + // Reserved 203 + TAG_DEVICE_LOCATION = 204, + TAG_WHITE_SPACE_MAP = 205, + TAG_FINE_TIMING_MEASUREMENT_PARAMETERS = 206, + // Reserved 207-220 + TAG_VENDOR_SPECIFIC = 221, + // Reserved 222-254 +}; + +/** + * A tagged parameter always consists of a tag number and length + */ +struct libwifi_tag_header { + uint8_t tag_num; + uint8_t tag_len; +} __attribute__((packed)); + +/* + * A tagged parameter will include a header as well as some body, + * depending on the tag number. The length of the body buffer is + * determined with the header.tag_len variable. + */ +struct libwifi_tagged_parameter { + struct libwifi_tag_header header; + unsigned char *body; +} __attribute__((packed)); + +/* + * A collection of total tagged parameters + */ +struct libwifi_tagged_parameters { + size_t length; + unsigned char *parameters; +} __attribute__((packed)); + +/* + * Vendor specific tagged parameters have an OUI and Sub-Type + * to determine their use + */ +struct libwifi_tag_vendor_header { + unsigned char oui[3]; + int8_t type; +} __attribute__((packed)); + +/** + * Add a tagged parameter to a list of frame tagged parameters. + * + * @param tagged_parameters A management frame's tagged parameters + * @param tagged_parameter The new tagged parameter + */ +int libwifi_add_tag(struct libwifi_tagged_parameters *tagged_parameters, + struct libwifi_tagged_parameter *tagged_parameter); + +/** + * Remove a tagged parameter from a list of frame tagged parameters. + * + * @param tagged_parameters A management frame's tagged parameters + * @param tag_number Number of the tag to remove + */ +int libwifi_remove_tag(struct libwifi_tagged_parameters *tagged_parameters, int tag_number); + +/** + * Create a tagged parameter from a tag number, length and data. + * This can be useful when generating tags on their own, for use with + * action frame body's. + * + * @param tagged_parameter A new tagged parameter struct + * @param tag_number Tagged parameter number + * @param tag_data The tag body + * @param tag_length Length of the tag body + * @return length of the created tag + */ +size_t libwifi_create_tag(struct libwifi_tagged_parameter *tagged_parameter, int tag_number, + const unsigned char *tag_data, size_t tag_length); + +/** + * Free a tagged parameters body + * + * @param tagged_parameter A used tagged parameter + */ +void libwifi_free_tag(struct libwifi_tagged_parameter *tagged_parameter); + +/** + * Dump a tagged parameter into a raw buffer, for use with other buffers + * or injection. + * + * @param tag A used tagged parameter struct + * @param buf A buffer for the raw data + * @param buf_len Length of buf + */ +size_t libwifi_dump_tag(struct libwifi_tagged_parameter *tag, unsigned char *buf, size_t buf_len); + +/** + * Add a tagged parameter via tag number and data to a management frame. + * + * @param tagged_parameters A management frame's tagged parameters + * @param tag_number Tagged parameter to add + * @param tag_data Data to copy into new tag + * @param tag_length Length of the new tag + * @return 0 on success, negative number on error + */ +int libwifi_quick_add_tag(struct libwifi_tagged_parameters *tagged_parameters, int tag_number, + const unsigned char *tag_data, size_t tag_length); + +#endif /* LIBWIFI_CORE_TAG_H */ diff --git a/src/libwifi/core/frame/tag_iterator.c b/src/libwifi/core/frame/tag_iterator.c new file mode 100644 index 0000000..c197752 --- /dev/null +++ b/src/libwifi/core/frame/tag_iterator.c @@ -0,0 +1,55 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "tag_iterator.h" + +#include +#include +#include + +int libwifi_tag_iterator_init(struct libwifi_tag_iterator *it, const void *tags_start, size_t data_len) { + it->tag_header = (struct libwifi_tag_header *) tags_start; + if (it->tag_header->tag_len < 0) { + return -EINVAL; + } + + it->tag_data = (unsigned char *) tags_start + sizeof(struct libwifi_tag_header); + it->_next_tag_header = (struct libwifi_tag_header *) (it->tag_data + it->tag_header->tag_len); + it->_frame_end = (unsigned char *) (tags_start) + data_len - 1; + + return 0; +} + +int libwifi_tag_iterator_next(struct libwifi_tag_iterator *it) { + unsigned char *next_th = (unsigned char *) it->_next_tag_header; + if (next_th >= it->_frame_end) { + return -1; + } + + it->tag_header = it->_next_tag_header; + if (it->tag_header->tag_len < 0) { + return -1; + } + + unsigned long bytes_left = (char *) it->_frame_end - (char *) it->tag_header; + if (it->tag_header->tag_len >= bytes_left) { + return -1; + } + + it->tag_data = ((unsigned char *) (it->tag_header)) + sizeof(struct libwifi_tag_header); + it->_next_tag_header = (struct libwifi_tag_header *) (it->tag_data + it->tag_header->tag_len); + + return it->tag_header->tag_num; +} diff --git a/src/libwifi/core/frame/tag_iterator.h b/src/libwifi/core/frame/tag_iterator.h new file mode 100644 index 0000000..ae2d4ba --- /dev/null +++ b/src/libwifi/core/frame/tag_iterator.h @@ -0,0 +1,53 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_TAGITERATOR_H +#define LIBWIFI_CORE_TAGITERATOR_H + +#include "../misc/byteswap.h" +#include "frame.h" +#include "tag.h" +#include + +/** + * A libwifi_tag_iterator is used to iterate through a list of tagged parameters + * in a wifi frame. + */ +struct libwifi_tag_iterator { + struct libwifi_tag_header *tag_header; + const unsigned char *tag_data; + struct libwifi_tag_header *_next_tag_header; + const unsigned char *_frame_end; +}; + +/** + * Initialise a libwifi frame tag iterator. + * + * @param it A libwifi tag iterator struct + * @param tags_start The beginning of a frame's tag data + * @param data_len The total length of the frame's tag data + * @return negative number on error, zero on success + */ +int libwifi_tag_iterator_init(struct libwifi_tag_iterator *it, const void *tags_start, size_t data_len); + +/** + * Iterate towards the next tagged parameter in a libwifi tag iterator. + * + * @param A libwifi tag iterator sturct, after being initalised + * @return The tag number of the next tag + */ +int libwifi_tag_iterator_next(struct libwifi_tag_iterator *it); + +#endif /* LIBWIFI_CORE_TAGITERATOR_H */ diff --git a/src/libwifi/core/misc/byteswap.h b/src/libwifi/core/misc/byteswap.h new file mode 100644 index 0000000..cab264f --- /dev/null +++ b/src/libwifi/core/misc/byteswap.h @@ -0,0 +1,31 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_BYTESWAP_H +#define LIBWIFI_CORE_BYTESWAP_H + +#include + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define BYTESWAP16(x) x +#define BYTESWAP32(x) x +#define BYTESWAP64(x) x +#else +#define BYTESWAP16(x) (__bswap_16(x)) +#define BYTESWAP32(x) (__bswap_32(x)) +#define BYTESWAP64(x) (__bswap_32(x)) +#endif + +#endif /* LIBWIFI_CORE_BYTESWAP_H */ diff --git a/src/libwifi/core/misc/epoch.c b/src/libwifi/core/misc/epoch.c new file mode 100644 index 0000000..d043f06 --- /dev/null +++ b/src/libwifi/core/misc/epoch.c @@ -0,0 +1,23 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "epoch.h" +#include + +unsigned long long libwifi_get_epoch(void) { + struct timespec spec; + clock_gettime(CLOCK_REALTIME, &spec); + return spec.tv_sec * 1000 + spec.tv_nsec / 1000; +} diff --git a/src/libwifi/core/misc/epoch.h b/src/libwifi/core/misc/epoch.h new file mode 100644 index 0000000..f8d312f --- /dev/null +++ b/src/libwifi/core/misc/epoch.h @@ -0,0 +1,26 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_EPOCH_H +#define LIBWIFI_CORE_EPOCH_H + +/** + * Get the current system time in epoch. + * + * @return current time in unix epoch. + */ +unsigned long long libwifi_get_epoch(void); + +#endif /* LIBWIFI_CORE_EPOCH_H */ diff --git a/src/libwifi/core/misc/llc.h b/src/libwifi/core/misc/llc.h new file mode 100644 index 0000000..9c8350d --- /dev/null +++ b/src/libwifi/core/misc/llc.h @@ -0,0 +1,33 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_LLC_H +#define LIBWIFI_CORE_LLC_H + +#include + +#define XEROX_OUI "\x00\x00\x00" + +#define LLC_TYPE_AUTH 0x888E + +struct libwifi_logical_link_ctrl { + uint8_t dsap; + uint8_t ssap; + uint8_t control; + unsigned char oui[3]; + uint16_t type; +} __attribute__((packed)); + +#endif /* LIBWIFI_CORE_LLC_H */ diff --git a/src/libwifi/core/misc/radiotap.h b/src/libwifi/core/misc/radiotap.h new file mode 100644 index 0000000..85ed7b8 --- /dev/null +++ b/src/libwifi/core/misc/radiotap.h @@ -0,0 +1,83 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_RADIOTAP_H +#define LIBWIFI_CORE_RADIOTAP_H + +#include + +#define LIBWIFI_MAX_RADIOTAP_LEN 128 +#define LIBWIFI_MAX_RADIOTAP_ANTENNAS 16 + +/** + * A channel field in radiotap consists of a 2-byte wide flags + * sub-field and a 2-byte wide frequency field + */ +struct libwifi_radiotap_channel { + uint16_t flags; + uint16_t freq; +} __attribute__((packed)); + +/** + * The radiotap antenna field consists of an antenna number and signal in dBm + */ +struct libwifi_radiotap_antenna { + uint8_t antenna_number; + int8_t signal; +} __attribute__((packed)); + +/** + * The radiotap MCS field is made up of 3 2-byte fields. + */ +struct libwifi_radiotap_mcs { + uint8_t known; + uint8_t flags; + uint8_t mcs; +} __attribute__((packed)); + +/** + * The radiotap timestamp field consists of a timestamp field, accuracy, unit and flags. + */ +struct libwifi_radiotap_timestamp { + uint64_t timestamp; + uint16_t accuracy; + uint8_t unit; + uint8_t flags; +} __attribute__((packed)); + +struct libwifi_radiotap_info { + // Header + uint32_t present; + // Body + struct libwifi_radiotap_channel channel; + int8_t rate_raw; + float rate; + uint8_t antenna_count; + struct libwifi_radiotap_antenna antennas[LIBWIFI_MAX_RADIOTAP_ANTENNAS]; + int8_t signal; + uint8_t flags; + uint32_t extended_flags; + uint16_t rx_flags; + uint16_t tx_flags; + struct libwifi_radiotap_mcs mcs; + int8_t tx_power; + struct libwifi_radiotap_timestamp timestamp; + uint8_t rts_retries; + uint8_t data_retries; + // Other + uint8_t length; +} __attribute__((packed)); + +#endif /* LIBWIFI_CORE_RADIOTAP_H */ diff --git a/src/libwifi/core/misc/security.h b/src/libwifi/core/misc/security.h new file mode 100644 index 0000000..6d97b13 --- /dev/null +++ b/src/libwifi/core/misc/security.h @@ -0,0 +1,289 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_SECURITY_H +#define LIBWIFI_CORE_SECURITY_H + +#include + +/* 802.1X Key Information Field Values */ +#define EAPOL_KEY_INFO_M1 0x008A +#define EAPOL_KEY_INFO_M2 0x010A +#define EAPOL_KEY_INFO_M3 0x13CA +#define EAPOL_KEY_INFO_M4 0x030A + +/* Sane maximum value for Cipher Suite Count */ +#define LIBWIFI_MAX_CIPHER_SUITES 6 + +/* Cipher Suite OUIs for WPA and RSN */ +#define MICROSOFT_OUI "\x00\x50\xF2" +#define CIPHER_SUITE_OUI "\x00\x0F\xAC" + +/* Common Microsoft Vendor Types */ +#define MICROSOFT_OUI_TYPE_WPA 1 +#define MICROSOFT_OUI_TYPE_WMM 2 +#define MICROSOFT_OUI_TYPE_WPS 4 + +/* Cipher Suite Values */ +#define CIPHER_SUITE_GROUP 0 /* WPA1/2 */ +#define CIPHER_SUITE_WEP40 1 /* WEP */ +#define CIPHER_SUITE_TKIP 2 /* WPA1/2 */ +#define CIPHER_SUITE_RESERVED 3 /* WPA1/2 */ +#define CIPHER_SUITE_CCMP128 4 /* WPA2 */ +#define CIPHER_SUITE_WEP104 5 /* WEP */ +#define CIPHER_SUITE_BIP_CMAC128 6 /* WPA2 */ +#define CIPHER_SUITE_NOTALLOWED 7 /* WPA2 */ +#define CIPHER_SUITE_GCMP128 8 /* WPA3 */ +#define CIPHER_SUITE_GCMP256 9 /* WPA3 */ +#define CIPHER_SUITE_CCMP256 10 /* WPA3 */ +#define CIPHER_SUITE_BIP_GMAC128 11 /* WPA3 */ +#define CIPHER_SUITE_BIP_GMAC256 12 /* WPA3 */ +#define CIPHER_SUITE_BIP_CMAC256 13 /* WPA3 */ + +/* Auth Key Management Suite Values */ +#define AKM_SUITE_RESERVED 0 /* WPA1/2 */ +#define AKM_SUITE_1X 1 /* WPA1/2 */ +#define AKM_SUITE_PSK 2 /* WPA1/2 */ +#define AKM_SUITE_1X_FT 3 /* WPA1/2 */ +#define AKM_SUITE_PSK_FT 4 /* WPA2 */ +#define AKM_SUITE_1X_SHA256 5 /* WPA2 */ +#define AKM_SUITE_PSK_SHA256 6 /* WPA2 */ +#define AKM_SUITE_TDLS 7 /* WPA2 */ +#define AKM_SUITE_SAE 8 /* WPA3 */ +#define AKM_SUITE_SAE_FT 9 /* WPA3 */ +#define AKM_SUITE_AP_PEER 10 /* WPA3 */ +#define AKM_SUITE_1X_SUITEB_SHA256 11 /* WPA3 */ +#define AKM_SUITE_1X_SUITEB_SHA384 12 /* WPA3 */ +#define AKM_SUITE_1X_FT_SHA384 13 /* WPA3 */ +#define AKM_SUITE_FILS_SHA256 14 /* WPA3 */ +#define AKM_SUITE_FILS_SHA384 15 /* WPA3 */ +#define AKM_SUITE_FILS_SHA256_FT 16 /* WPA3 */ +#define AKM_SUITE_FILS_SHA384_FT 17 /* WPA3 */ +#define AKM_SUITE_OWE 18 /* WPA3 */ +#define AKM_PSK_SHA384_FT 19 /* WPA3 */ +#define AKM_PSK_SHA384 20 /* WPA3 */ + +/* Authentication Scheme Values */ +#define AUTH_OPEN 0 +#define AUTH_SHARED_KEY 1 +#define AUTH_FAST_BSS 2 +#define AUTH_SAE 3 +#define AUTH_VENDOR 65535 + +/* libwifi Security Type Values for libwifi_bss encryption_info */ +#define WEP (1ULL << 1) +#define WPA (1ULL << 2) +#define WPA2 (1ULL << 3) +#define WPA3 (1ULL << 4) + +/* libwifi Group or Multicast Cipher Values for libwifi_bss encryption_info */ +#define LIBWIFI_GROUP_CIPHER_SUITE_WEP40 (1ULL << 5) +#define LIBWIFI_GROUP_CIPHER_SUITE_TKIP (1ULL << 6) +#define LIBWIFI_GROUP_CIPHER_SUITE_RESERVED (1ULL << 7) +#define LIBWIFI_GROUP_CIPHER_SUITE_CCMP128 (1ULL << 8) +#define LIBWIFI_GROUP_CIPHER_SUITE_WEP104 (1ULL << 9) +#define LIBWIFI_GROUP_CIPHER_SUITE_BIP_CMAC128 (1ULL << 10) +#define LIBWIFI_GROUP_CIPHER_SUITE_NOTALLOWED (1ULL << 11) +#define LIBWIFI_GROUP_CIPHER_SUITE_GCMP128 (1ULL << 12) +#define LIBWIFI_GROUP_CIPHER_SUITE_GCMP256 (1ULL << 13) +#define LIBWIFI_GROUP_CIPHER_SUITE_CCMP256 (1ULL << 14) +#define LIBWIFI_GROUP_CIPHER_SUITE_BIP_GMAC128 (1ULL << 15) +#define LIBWIFI_GROUP_CIPHER_SUITE_BIP_GMAC256 (1ULL << 16) +#define LIBWIFI_GROUP_CIPHER_SUITE_BIP_CMAC256 (1ULL << 17) + +/* libwifi Pairwise or Unicast Cipher Values for libwifi_bss encryption_info */ +#define LIBWIFI_PAIRWISE_SUITE_GROUP (1ULL << 18) +#define LIBWIFI_PAIRWISE_CIPHER_SUITE_WEP40 (1ULL << 19) +#define LIBWIFI_PAIRWISE_CIPHER_SUITE_TKIP (1ULL << 20) +#define LIBWIFI_PAIRWISE_CIPHER_SUITE_RESERVED (1ULL << 21) +#define LIBWIFI_PAIRWISE_CIPHER_SUITE_CCMP128 (1ULL << 22) +#define LIBWIFI_PAIRWISE_CIPHER_SUITE_WEP104 (1ULL << 23) +#define LIBWIFI_PAIRWISE_CIPHER_SUITE_BIP_CMAC128 (1ULL << 24) +#define LIBWIFI_PAIRWISE_CIPHER_SUITE_NOTALLOWED (1ULL << 25) +#define LIBWIFI_PAIRWISE_CIPHER_SUITE_GCMP128 (1ULL << 26) +#define LIBWIFI_PAIRWISE_CIPHER_SUITE_GCMP256 (1ULL << 27) +#define LIBWIFI_PAIRWISE_CIPHER_SUITE_CCMP256 (1ULL << 28) +#define LIBWIFI_PAIRWISE_CIPHER_SUITE_BIP_GMAC128 (1ULL << 29) +#define LIBWIFI_PAIRWISE_CIPHER_SUITE_BIP_GMAC256 (1ULL << 30) +#define LIBWIFI_PAIRWISE_CIPHER_SUITE_BIP_CMAC256 (1ULL << 31) + +/* libwifi Auth Key Management Values for libwifi_bss encryption_info */ +#define LIBWIFI_AKM_SUITE_RESERVED (1ULL << 32) +#define LIBWIFI_AKM_SUITE_1X (1ULL << 33) +#define LIBWIFI_AKM_SUITE_PSK (1ULL << 34) +#define LIBWIFI_AKM_SUITE_1X_FT (1ULL << 35) +#define LIBWIFI_AKM_SUITE_PSK_FT (1ULL << 36) +#define LIBWIFI_AKM_SUITE_1X_SHA256 (1ULL << 37) +#define LIBWIFI_AKM_SUITE_PSK_SHA256 (1ULL << 39) +#define LIBWIFI_AKM_SUITE_TDLS (1ULL << 40) +#define LIBWIFI_AKM_SUITE_SAE (1ULL << 41) +#define LIBWIFI_AKM_SUITE_SAE_FT (1ULL << 42) +#define LIBWIFI_AKM_SUITE_AP_PEER (1ULL << 43) +#define LIBWIFI_AKM_SUITE_1X_SUITEB_SHA256 (1ULL << 44) +#define LIBWIFI_AKM_SUITE_1X_SUITEB_SHA384 (1ULL << 45) +#define LIBWIFI_AKM_SUITE_1X_FT_SHA384 (1ULL << 46) +#define LIBWIFI_AKM_SUITE_FILS_SHA256 (1ULL << 47) +#define LIBWIFI_AKM_SUITE_FILS_SHA384 (1ULL << 48) +#define LIBWIFI_AKM_SUITE_FILS_SHA256_FT (1ULL << 49) +#define LIBWIFI_AKM_SUITE_FILS_SHA384_FT (1ULL << 50) +#define LIBWIFI_AKM_SUITE_OWE (1ULL << 51) +#define LIBWIFI_AKM_PSK_SHA384_FT (1ULL << 52) +#define LIBWIFI_AKM_PSK_SHA384 (1ULL << 53) + +/* libwifi Authentication Scheme Values for libwifi_bss encryption_info */ +#define LIBWIFI_AUTH_OPEN (1ULL << 54) +#define LIBWIFI_AUTH_SHARED_KEY (1ULL << 55) +#define LIBWIFI_AUTH_FAST_BSS (1ULL << 56) +#define LIBWIFI_AUTH_SAE (1ULL << 57) +#define LIBWIFI_AUTH_VENDOR (1ULL << 58) + +/* libwifi RSN Capability flags */ +#define LIBWIFI_RSN_CAPAB_PREAUTH (1 << 0) +#define LIBWIFI_RSN_CAPAB_PAIRWISE (1 << 1) +#define LIBWIFI_RSN_CAPAB_PTKSA_REPLAY (1 << 2 | 1 << 3) +#define LIBWIFI_RSN_CAPAB_GTKSA_REPLAY (1 << 4 | 1 << 5) +#define LIBWIFI_RSN_CAPAB_MFP_REQUIRED (1 << 6) +#define LIBWIFI_RSN_CAPAB_MFP_CAPABLE (1 << 7) +#define LIBWIFI_RSN_CAPAB_JOINT_RSNA (1 << 8) +#define LIBWIFI_RSN_CAPAB_PEERKEY (1 << 9) +#define LIBWIFI_RSN_CAPAB_EXT_KEY_ID (1 << 13) + +/** + * libwifi Representation of a WPA or RSN cipher suite + * ┌────────────────────────┬────────────┐ + * │ OUI │ Suite Type │ + * ├────────────────────────┼────────────┤ + * │ 3 Bytes │ 1 Byte │ + * └────────────────────────┴────────────┘ + * + */ +struct libwifi_cipher_suite { + unsigned char oui[3]; + uint8_t suite_type; +} __attribute__((packed)); + +/** + * libwifi Representation of a Microsoft WPA Information Element + * ┌───────────────────────────────────┐ + * │ Version │ ── 2 Bytes + * ├───────────────────────────────────┤ + * │ Multicast Cipher Suite │ ── 4 Bytes + * ├───────────────────────────────────┤ + * │ Unicast Cipher Suite Count │ ── 2 Bytes + * ├───────────────────────────────────┤ + * │ Unicast Cipher Suites │ ── 4 to 12 Bytes + * ├───────────────────────────────────┤ + * │ Auth Key Management Suite Count │ ── 2 Bytes + * ├───────────────────────────────────┤ + * │ Auth Key Management Suites │ ── 4 to 12 Bytes + * └───────────────────────────────────┘ + */ +struct libwifi_wpa_info { + uint16_t wpa_version; + struct libwifi_cipher_suite multicast_cipher_suite; + uint16_t num_unicast_cipher_suites; + struct libwifi_cipher_suite unicast_cipher_suites[LIBWIFI_MAX_CIPHER_SUITES]; + uint16_t num_auth_key_mgmt_suites; + struct libwifi_cipher_suite auth_key_mgmt_suites[LIBWIFI_MAX_CIPHER_SUITES]; +} __attribute__((packed)); + +/** + * libwifi Representation of a 802.11 RSN Information Element + * ┌───────────────────────────────────┐ + * │ Version │ ── 2 Bytes + * ├───────────────────────────────────┤ + * │ Group Cipher Suite │ ── 4 Bytes + * ├───────────────────────────────────┤ + * │ Pairwise Cipher Suite Count │ ── 2 Bytes + * ├───────────────────────────────────┤ + * │ Pairwise Cipher Suites │ ── 4 to 12 Bytes + * ├───────────────────────────────────┤ + * │ Auth Key Management Suite Count │ ── 2 Bytes + * ├───────────────────────────────────┤ + * │ Auth Key Management Suites │ ── 4 to 12 Bytes + * ├───────────────────────────────────┤ + * │ RSN Capabilities │ ── 2 Bytes + * └───────────────────────────────────┘ + */ +struct libwifi_rsn_info { + uint16_t rsn_version; + struct libwifi_cipher_suite group_cipher_suite; + int num_pairwise_cipher_suites; + struct libwifi_cipher_suite pairwise_cipher_suites[LIBWIFI_MAX_CIPHER_SUITES]; + int num_auth_key_mgmt_suites; + struct libwifi_cipher_suite auth_key_mgmt_suites[LIBWIFI_MAX_CIPHER_SUITES]; + uint16_t rsn_capabilities; +} __attribute__((packed)); + +/* + * libwifi Representation of the 802.1X/EAPOL Key Information section + * ┌───────────────────────────────────┐ + * │ Key Information │ ── 2 Bytes + * ├───────────────────────────────────┤ + * │ Key Length │ ── 2 Bytes + * ├───────────────────────────────────┤ + * │ Replay Counter │ ── 8 Bytes + * ├───────────────────────────────────┤ + * │ WPA Key Nonce │ ── 32 Bytes + * ├───────────────────────────────────┤ + * │ WPA Key IV │ ── 16 Bytes + * ├───────────────────────────────────┤ + * │ WPA Key RSC │ ── 8 Bytes + * ├───────────────────────────────────┤ + * │ WPA Key ID │ ── 8 Bytes + * ├───────────────────────────────────┤ + * │ WPA Key MIC │ ── 16 Bytes + * ├───────────────────────────────────┤ + * │ WPA Key Data Length │ ── 4 Bytes + * ├───────────────────────────────────┤ + * │ WPA Key Data │ ── Variable + * └───────────────────────────────────┘ + */ +struct libwifi_wpa_key_info { + uint16_t information; + uint16_t key_length; + uint64_t replay_counter; + unsigned char nonce[32]; + unsigned char iv[16]; + unsigned char rsc[8]; + unsigned char id[8]; + unsigned char mic[16]; + uint16_t key_data_length; + unsigned char *key_data; +} __attribute__((packed)); + +/** + * libwifi Representation of the encapsulating 802.1X data in an EAPOL frame + * ┌─────────────────┐ + * │ Version │ ── 1 Byte + * ├─────────────────┤ + * │ Type │ ── 1 Byte + * ├─────────────────┤ + * │ Length │ ── 2 Bytes + * ├─────────────────┤ + * │ Descriptor │ ── 1 Byte + * ├─────────────────┤ + * │ Key Information │ ── See libwifi_wpa_key_info + * └─────────────────┘ + */ +struct libwifi_wpa_auth_data { + uint8_t version; + uint8_t type; + uint16_t length; + uint8_t descriptor; + struct libwifi_wpa_key_info key_info; +} __attribute__((packed)); + +#endif /* LIBWIFI_CORE_SECURITY_H */ diff --git a/src/libwifi/core/misc/types.h b/src/libwifi/core/misc/types.h new file mode 100644 index 0000000..3532183 --- /dev/null +++ b/src/libwifi/core/misc/types.h @@ -0,0 +1,218 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_CORE_TYPES_H +#define LIBWIFI_CORE_TYPES_H + +#include "../../core/misc/byteswap.h" + +/* 802.11 Management Frame "reason code" fixed parameter values */ +enum libwifi_reason_codes { + REASON_UNSPECIFIED_FAILURE = 1, + REASON_PREVIOUS_AUTH_INVALID = 2, + REASON_STA_LEAVING_ESS = 3, + REASON_INACTIVE = 4, + REASON_TOO_MANY_STAS = 5, + REASON_CLASS_2_FRAME = 6, + REASON_CLASS_3_FRAME = 7, + REASON_STA_LEAVING_BSS = 8, + REASON_STA_REQUESTING_REASSOC_NOT_AUTHED = 9, + REASON_UNNACCEPTABLE_POWER_CAPABILITY = 10, + REASON_UNNACCEPTABLE_CHANNELS = 11, + REASON_BSS_TRANSITION_MGMT = 12, + REASON_INVALID_ELEMENT = 13, + REASON_MIC_FAILURE = 14, + REASON_FOURWAY_HANDSHAKE_TIMEOUT = 15, + REASON_GROUPKEY_HANDSHAKE_TIMEOUT = 16, + REASON_INVALID_FOURWAY = 17, + REASON_INVALID_GROUP_CIPHER = 18, + REASON_INVALID_PAIRWISE_CIPHER = 19, + REASON_INVALID_AKMP = 20, + REASON_UNSUPPORTED_RSNE_VERSION = 21, + REASON_INVALID_RSNE_CAPABILITIES = 22, + REASON_INVALID_8021X_AUTH = 23, + REASON_CIPHER_SUITE_REJECTED = 24, + REASON_TDLS_DIRECT_LINK_TEARDOWN_UNREACHABLE = 25, + REASON_TDLS_DIRECT_LINK_TEARDOWN_UNSPECIFIED = 26, + REASON_SSP_REQUEST = 27, + REASON_LACKS_SSP_ROAMING = 28, + REASON_CIPHER_OR_AKM_REQUIRED = 29, + REASON_SERVICE_NOT_AUTHORIZED = 30, + REASON_SERVICE_CHANGE_PRECLUDES_TS = 31, + REASON_UNSPECIFIED_QOS = 32, + REASON_INSUFFICIENT_BANDWIDTH = 33, + REASON_EXCESSIVE_ACKS_REQUIRED = 34, + REASON_TXOPS_EXCEEDED = 35, + REASON_STA_LEAVING = 36, + REASON_END_TS = 37, + REASON_UNKNOWN_TS_OR_BA = 38, + REASON_TIMEOUT = 39, + REASON_PEERKEY_MISMATCH = 45, + REASON_PEER_INITIATED = 46, + REASON_AP_INITIATED = 47, + REASON_INVALID_FT_ACTION_FRAMECOUNT = 48, + REASON_INVALID_PMKI = 49, + REASON_INVALID_MDE = 50, + REASON_INVALID_FTE = 51, + REASON_MESH_PEERING_CANCELED = 52, + REASON_MESH_MAX_PEERS = 53, + REASON_MESH_CONFIGURATION_POLICY_VIOLATION = 54, + REASON_MESH_CLOSE_RCVD = 55, + REASON_MESH_MAX_RETRIES = 56, + REASON_MESH_CONFIRM_TIMEOUT = 57, + REASON_MESH_INVALID_GTK = 58, + REASON_MESH_INCONSISTENT_PARAMETERS = 59, + REASON_MESH_INVALID_SECURITY_CAPABILITY = 60, + REASON_MESH_PATH_ERROR_NO_PROXY_INFORMATION = 61, + REASON_MESH_PATH_ERROR_NO_FORWARDING_INFORMATION = 62, + REASON_MESH_PATH_ERROR_DESTINATION_UNREACHABLE = 63, + REASON_MAC_ADDRESS_ALREADY_EXISTS_IN_MBSS = 64, + REASON_MESH_CHANNEL_SWITCH_REGULATORY_REQUIREMENTS = 65, + REASON_MESH_CHANNEL_SWITCH_UNSPECIFIED = 66, +}; + +/* 802.11 Management Frame "status code" fixed parameter values */ +enum libwifi_status_codes { + STATUS_SUCCESS = 0, + STATUS_REFUSED = 1, + STATUS_TDLS_REJECTED_ALTERNATIVE_PROVIDED = 2, + // Reserved = 4, + STATUS_SECURITY_DISABLED = 5, + STATUS_UNACCEPTABLE_LIFETIME = 6, + STATUS_NOT_IN_SAME_BSS = 7, + // Reserved = 8, + // Reserved = 9, + STATUS_REFUSED_CAPABILITIES_MISMATCH = 10, + STATUS_DENIED_NO_ASSOCIATION_EXISTS = 11, + STATUS_DENIED_OTHER_REASON = 12, + STATUS_UNSUPPORTED_AUTH_ALGORITHM = 13, + STATUS_TRANSACTION_SEQUENCE_ERROR = 14, + STATUS_CHALLENGE_FAILURE = 15, + STATUS_REJECTED_SEQUENCE_TIMEOUT = 16, + STATUS_DENIED_NO_MORE_STAS = 17, + STATUS_REFUSED_BASIC_RATES_MISMATCH = 18, + STATUS_DENIED_NO_SHORT_PREAMBLE_SUPPORT = 19, + // Reserved = 20, + // Reserved = 21, + STATUS_REJECTED_SPECTRUM_MANAGEMENT_REQUIRED = 22, + STATUS_REJECTED_BAD_POWER_CAPABILITY = 23, + STATUS_REJECTED_BAD_SUPPORTED_CHANNELS = 24, + STATUS_DENIED_NO_SHORT_SLOT_TIME_SUPPORT = 25, + // Reserved = 26, + STATUS_DENIED_NO_HT_SUPPORT = 27, + STATUS_R0KH_UNREACHABLE = 28, + STATUS_DENIED_PCO_TIME_NOT_SUPPORTED = 29, + STATUS_REFUSED_TEMPORARILY = 30, + STATUS_ROBUST_MANAGEMENT_POLICY_VIOLATION = 31, + STATUS_UNSPECIFIED_QOS_FAILURE = 32, + STATUS_DENIED_INSUFFICIENT_BANDWIDTH = 33, + STATUS_DENIED_POOR_CHANNEL_CONDITIONS = 34, + STATUS_DENIED_QOS_NOT_SUPPORTED = 35, + // Reserved = 36, + STATUS_REQUEST_DECLINED = 37, + STATUS_INVALID_PARAMETERS = 38, + STATUS_REJECTED_WITH_SUGGESTED_CHANGES = 39, + STATUS_STATUS_INVALID_ELEMENT = 40, + STATUS_STATUS_INVALID_GROUP_CIPHER = 41, + STATUS_STATUS_INVALID_PAIRWISE_CIPHER = 42, + STATUS_STATUS_INVALID_AKMP = 43, + STATUS_UNSUPPORTED_RSNE_VERSION = 44, + STATUS_INVALID_RSNE_CAPABILITIES = 45, + STATUS_STATUS_CIPHER_OUT_OF_POLICY = 46, + STATUS_REJECTED_FOR_DELAY_PERIOD = 47, + STATUS_DLS_NOT_ALLOWED = 48, + STATUS_NOT_PRESENT = 49, + STATUS_NOT_QOS_STA = 50, + STATUS_DENIED_LISTEN_INTERVAL_TOO_LARGE = 51, + STATUS_STATUS_INVALID_FT_ACTION_FRAME_COUNT = 52, + STATUS_STATUS_INVALID_PMKID = 53, + STATUS_STATUS_INVALID_MDE = 54, + STATUS_STATUS_INVALID_FTE = 55, + STATUS_REQUESTED_TCLAS_NOT_SUPPORTED = 56, + STATUS_INSUFFICIENT_TCLAS_PROCESSING_RESOURCES = 57, + STATUS_TRY_ANOTHER_BSS = 58, + STATUS_GAS_ADVERTISEMENT_PROTOCOL_NOT_SUPPORTED = 59, + STATUS_NO_OUTSTANDING_GAS_REQUEST = 60, + STATUS_GAS_RESPONSE_NOT_RECEIVED_FROM = 61, + STATUS_GAS_QUERY_TIMEOUT = 62, + STATUS_GAS_QUERY_RESPONSE_TOO_ = 63, + STATUS_REJECTED_HOME_WITH_SUGGESTED_CHANGES = 64, + STATUS_SERVER_UNREACHABLE = 65, + // Reserved = 66, + STATUS_REJECTED_FOR_SSP_PERMISSIONS = 67, + STATUS_REFUSED_UNAUTHENTICATED_ACCESS_NOT_SUPPORTED = 68, + // Reserved = 69, + // Reserved = 70, + // Reserved = 71, + STATUS_INVALID_RSNE = 72, + STATUS_U_APSD_COEXISTANCE_NOT_SUPPORTED = 73, + STATUS_U_APSD_COEX_MODE_NOT_SUPPORTED = 74, + STATUS_BAD_INTERVAL_WITH_U_APSD_COEX = 75, + STATUS_ANTI_CLOGGING_TOKEN_REQUIRED = 76, + STATUS_UNSUPPORTED_FINITE_CYCLIC_GROUP = 77, + STATUS_CANNOT_FIND_ALTERNATIVE_TBTT = 78, + STATUS_TRANSMISSION_FAILURE = 79, + STATUS_REQUESTED_TCLAS_NOT_SUPPORTED_2 = 80, + STATUS_TCLAS_RESOURCES_EXHAUSTED = 81, + STATUS_REJECTED_WITH_SUGGESTED_BSS_TRANSITION = 82, + STATUS_REJECT_WITH_SCHEDULE = 83, + STATUS_REJECT_NO_WAKEUP_SPECIFIED = 84, + STATUS_SUCCESS_POWER_SAVE_MODE = 85, + STATUS_PENDING_ADMITTING_FST_SESSION = 86, + STATUS_PERFORMING_FST_NOW = 87, + STATUS_PENDING_GAP_IN_BA_WINDOW = 88, + STATUS_REJECT_U_PID_SETTING = 89, + // Reserved = 90, + // Reserved = 91, + STATUS_REFUSED_EXTERNAL_REASON = 92, + STATUS_REFUSED_AP_OUT_OF_MEMORY = 93, + STATUS_REJECTED_EMERGENCY_SERVICES_NOT_SUPPORTED = 94, + STATUS_QUERY_RESPONSE_OUTSTANDING = 95, + STATUS_REJECT_DSE_BAND = 96, + STATUS_TCLAS_PROCESSING_TERMINATED = 97, + STATUS_TS_SCHEDULE_CONFLICT = 98, + STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL = 99, + STATUS_MCCAOP_RESERVATION_CONFLICT = 100, + STATUS_MAF_LIMIT_EXCEEDED = 101, + STATUS_MCCA_TRACK_LIMIT_EXCEEDED = 102, + STATUS_DENIED_DUE_TO_SPECTRUM_MANAGEMENT = 103, + STATUS_DENIED_VHT_NOT_SUPPORTED = 104, + STATUS_ENABLEMENT_DENIED = 105, + STATUS_RESTRICTION_FROM_AUTHORIZED_GDB = 106, + STATUS_AUTHORIZATION_DEENABLED = 107, + // Reserved = 108–65535 +}; + +/* Defined capabilities_information fixed parameter values */ +#define libwifi_check_capabilities(x, cap) (BYTESWAP16(x) & (1 << cap)) +enum libwifi_capabilities { + CAPABILITIES_ESS = 0, + CAPABILITIES_IBSS = 1, + CAPABILITIES_POLL = 2, + CAPABILITIES_POLL_REQ = 3, + CAPABILITIES_PRIVACY = 4, + CAPABILITIES_SHORT_PREAMBLE = 5, + CAPABILITIES_PBCC = 6, + CAPABILITIES_CHAN_AGILITY = 7, + CAPABILITIES_SPECTRUM_AGILITY = 8 & (8 >> 1), + CAPABILITIES_SHORT_SLOT = 10, + CAPABILITIES_POWER_SAVE = 11, + CAPABILITIES_MEASUREMENT = 12, + CAPABILITIES_DSSS_OFDM = 13, + CAPABILITIES_DELAYED_ACK = 14, + CAPABILITIES_IMMEDIATE_ACK = 15, +}; + +#endif /* LIBWIFI_CORE_TYPES_H */ diff --git a/src/libwifi/core/radiotap/COPYING b/src/libwifi/core/radiotap/COPYING new file mode 100644 index 0000000..4cc12c2 --- /dev/null +++ b/src/libwifi/core/radiotap/COPYING @@ -0,0 +1,14 @@ +Copyright (c) 2007-2009 Andy Green +Copyright (c) 2007-2009 Johannes Berg + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/src/libwifi/core/radiotap/platform.h b/src/libwifi/core/radiotap/platform.h new file mode 100644 index 0000000..e0ad99f --- /dev/null +++ b/src/libwifi/core/radiotap/platform.h @@ -0,0 +1,81 @@ +#include +#include +#include + +#if defined(linux) || defined(Linux) || defined(__linux__) || defined(__linux) || defined(__gnu_linux__) +#include +#if defined(__UCLIBC__) +#include +#ifndef le16toh +#define le16toh __le16_to_cpu +#endif +#ifndef le32toh +#define le32toh __le32_to_cpu +#endif +#endif +#endif + +#if defined(__CYGWIN32__) || defined(CYGWIN) +#include +#include +#endif + +#if defined(__APPLE__) +#include +#endif + +#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__MidnightBSD__) || \ + defined(__NetBSD__) +#include +#include +#endif + +#if defined(__SVR4) && defined(__sun__) +#include +#include +#endif + +#ifndef le16_to_cpu +#define le16_to_cpu le16toh +#endif + +#ifndef le32_to_cpu +#define le32_to_cpu le32toh +#endif + +#if defined(_MSC_VER) +// Microsoft +#define EXPORT __declspec(dllexport) +#define IMPORT __declspec(dllimport) +#elif defined(__GNUC__) || defined(__llvm__) || defined(__clang__) || defined(__INTEL_COMPILER) +#define EXPORT __attribute__((visibility("default"))) +#define IMPORT +#else +// do nothing and hope for the best? +#define EXPORT +#define IMPORT +#pragma warning Unknown dynamic link import / export semantics. +#endif + +#if defined(RADIOTAP_FAST_UNALIGNED_ACCESS) +#define get_unaligned(p) \ + __extension__({ \ + struct packed_dummy_struct { \ + typeof(*(p)) __val; \ + } __attribute__((packed)) *__ptr = (void *) (p); \ + \ + __ptr->__val; \ + }) +#else +#define get_unaligned(p) \ + __extension__({ \ + typeof(*(p)) __tmp; \ + memmove(&__tmp, (p), sizeof(*(p))); \ + __tmp; \ + }) +#endif + +#define get_unaligned_le16(p) le16_to_cpu(get_unaligned((uint16_t *) (p))) +#define get_unaligned_le32(p) le32_to_cpu(get_unaligned((uint32_t *) (p))) + +#define UNALIGNED_ADDRESS(x) ((void *) (x)) diff --git a/src/libwifi/core/radiotap/radiotap.c b/src/libwifi/core/radiotap/radiotap.c new file mode 100644 index 0000000..5d46223 --- /dev/null +++ b/src/libwifi/core/radiotap/radiotap.c @@ -0,0 +1,469 @@ +/* + * Radiotap parser + * + * Copyright 2007 Andy Green + * Copyright 2009 Johannes Berg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Alternatively, this software may be distributed under the terms of ISC + * license, see COPYING for more details. + */ +#include "platform.h" +#include "radiotap_iter.h" + +/* function prototypes and related defs are in radiotap_iter.h */ + +static const struct radiotap_align_size rtap_namespace_sizes[] = { + [IEEE80211_RADIOTAP_TSFT] = + { + .align = 8, + .size = 8, + }, + [IEEE80211_RADIOTAP_FLAGS] = + { + .align = 1, + .size = 1, + }, + [IEEE80211_RADIOTAP_RATE] = + { + .align = 1, + .size = 1, + }, + [IEEE80211_RADIOTAP_CHANNEL] = + { + .align = 2, + .size = 4, + }, + [IEEE80211_RADIOTAP_FHSS] = + { + .align = 2, + .size = 2, + }, + [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = + { + .align = 1, + .size = 1, + }, + [IEEE80211_RADIOTAP_DBM_ANTNOISE] = + { + .align = 1, + .size = 1, + }, + [IEEE80211_RADIOTAP_LOCK_QUALITY] = + { + .align = 2, + .size = 2, + }, + [IEEE80211_RADIOTAP_TX_ATTENUATION] = + { + .align = 2, + .size = 2, + }, + [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = + { + .align = 2, + .size = 2, + }, + [IEEE80211_RADIOTAP_DBM_TX_POWER] = + { + .align = 1, + .size = 1, + }, + [IEEE80211_RADIOTAP_ANTENNA] = + { + .align = 1, + .size = 1, + }, + [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = + { + .align = 1, + .size = 1, + }, + [IEEE80211_RADIOTAP_DB_ANTNOISE] = + { + .align = 1, + .size = 1, + }, + [IEEE80211_RADIOTAP_RX_FLAGS] = + { + .align = 2, + .size = 2, + }, + [IEEE80211_RADIOTAP_TX_FLAGS] = + { + .align = 2, + .size = 2, + }, + [IEEE80211_RADIOTAP_RTS_RETRIES] = + { + .align = 1, + .size = 1, + }, + [IEEE80211_RADIOTAP_DATA_RETRIES] = + { + .align = 1, + .size = 1, + }, + [IEEE80211_RADIOTAP_MCS] = + { + .align = 1, + .size = 3, + }, + [IEEE80211_RADIOTAP_AMPDU_STATUS] = + { + .align = 4, + .size = 8, + }, + [IEEE80211_RADIOTAP_VHT] = + { + .align = 2, + .size = 12, + }, + [IEEE80211_RADIOTAP_TIMESTAMP] = + { + .align = 8, + .size = 12, + }, + /* + * add more here as they are defined in radiotap.h + */ +}; + +const struct ieee80211_radiotap_namespace radiotap_ns = { + .n_bits = sizeof(rtap_namespace_sizes) / sizeof(rtap_namespace_sizes[0]), + .align_size = rtap_namespace_sizes, +}; + +/** + * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization + * @iterator: radiotap_iterator to initialize + * @radiotap_header: radiotap header to parse + * @max_length: total length we can parse into (eg, whole packet length) + * + * Returns: 0 or a negative error code if there is a problem. + * + * This function initializes an opaque iterator struct which can then + * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap + * argument which is present in the header. It knows about extended + * present headers and handles them. + * + * How to use: + * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator + * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) + * checking for a good 0 return code. Then loop calling + * __ieee80211_radiotap_iterator_next()... it returns either 0, + * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem. + * The iterator's @this_arg member points to the start of the argument + * associated with the current argument index that is present, which can be + * found in the iterator's @this_arg_index member. This arg index corresponds + * to the IEEE80211_RADIOTAP_... defines. + * + * Radiotap header length: + * You can find the CPU-endian total radiotap header length in + * iterator->max_length after executing ieee80211_radiotap_iterator_init() + * successfully. + * + * Alignment Gotcha: + * You must take care when dereferencing iterator.this_arg + * for multibyte types... the pointer is not aligned. Use + * get_unaligned((type *)iterator.this_arg) to dereference + * iterator.this_arg for type "type" safely on all arches. + * + * Example code: parse.c + */ + +EXPORT +int ieee80211_radiotap_iterator_init(struct ieee80211_radiotap_iterator *iterator, + struct ieee80211_radiotap_header *radiotap_header, int max_length, + const struct ieee80211_radiotap_vendor_namespaces *vns) { + /* must at least have the radiotap header */ + if (max_length < (int) sizeof(struct ieee80211_radiotap_header)) + return -EINVAL; + + /* Linux only supports version 0 radiotap format */ + if (radiotap_header->it_version) + return -EINVAL; + + /* sanity check for allowed length and radiotap length field */ + if (max_length < get_unaligned_le16(UNALIGNED_ADDRESS(&radiotap_header->it_len))) + return -EINVAL; + + iterator->_rtheader = radiotap_header; + iterator->_max_length = get_unaligned_le16(UNALIGNED_ADDRESS(&radiotap_header->it_len)); + iterator->_arg_index = 0; + iterator->_bitmap_shifter = get_unaligned_le32(UNALIGNED_ADDRESS(&radiotap_header->it_present)); + iterator->_arg = (uint8_t *) radiotap_header + sizeof(*radiotap_header); + iterator->_reset_on_ext = 0; +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 9 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Waddress-of-packed-member" +#endif + iterator->_next_bitmap = UNALIGNED_ADDRESS(&radiotap_header->it_present); +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 9 +#pragma GCC diagnostic pop +#endif + iterator->_next_bitmap++; + iterator->_vns = vns; + iterator->current_namespace = &radiotap_ns; + iterator->is_radiotap_ns = 1; +#ifdef RADIOTAP_SUPPORT_OVERRIDES + iterator->n_overrides = 0; + iterator->overrides = NULL; +#endif + + /* find payload start allowing for extended bitmap(s) */ + + if (iterator->_bitmap_shifter & (1 << IEEE80211_RADIOTAP_EXT)) { + if ((unsigned long) iterator->_arg - (unsigned long) iterator->_rtheader + sizeof(uint32_t) > + (unsigned long) iterator->_max_length) + return -EINVAL; + while (get_unaligned_le32(iterator->_arg) & (1 << IEEE80211_RADIOTAP_EXT)) { + iterator->_arg += sizeof(uint32_t); + + /* + * check for insanity where the present bitmaps + * keep claiming to extend up to or even beyond the + * stated radiotap header length + */ + + if ((unsigned long) iterator->_arg - (unsigned long) iterator->_rtheader + sizeof(uint32_t) > + (unsigned long) iterator->_max_length) + return -EINVAL; + } + + iterator->_arg += sizeof(uint32_t); + + /* + * no need to check again for blowing past stated radiotap + * header length, because ieee80211_radiotap_iterator_next + * checks it before it is dereferenced + */ + } + + iterator->this_arg = iterator->_arg; + + /* we are all initialized happily */ + + return 0; +} + +static void find_ns(struct ieee80211_radiotap_iterator *iterator, uint32_t oui, uint8_t subns) { + int i; + + iterator->current_namespace = NULL; + + if (!iterator->_vns) + return; + + for (i = 0; i < iterator->_vns->n_ns; i++) { + if (iterator->_vns->ns[i].oui != oui) + continue; + if (iterator->_vns->ns[i].subns != subns) + continue; + + iterator->current_namespace = &iterator->_vns->ns[i]; + break; + } +} + +#ifdef RADIOTAP_SUPPORT_OVERRIDES +static int find_override(struct ieee80211_radiotap_iterator *iterator, int *align, int *size) { + int i; + + if (!iterator->overrides) + return 0; + + for (i = 0; i < iterator->n_overrides; i++) { + if (iterator->_arg_index == iterator->overrides[i].field) { + *align = iterator->overrides[i].align; + *size = iterator->overrides[i].size; + if (!*align) /* erroneous override */ + return 0; + return 1; + } + } + + return 0; +} +#endif + +/** + * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg + * @iterator: radiotap_iterator to move to next arg (if any) + * + * Returns: 0 if there is an argument to handle, + * -ENOENT if there are no more args or -EINVAL + * if there is something else wrong. + * + * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) + * in @this_arg_index and sets @this_arg to point to the + * payload for the field. It takes care of alignment handling and extended + * present fields. @this_arg can be changed by the caller (eg, + * incremented to move inside a compound argument like + * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in + * little-endian format whatever the endianness of your CPU. + * + * Alignment Gotcha: + * You must take care when dereferencing iterator.this_arg + * for multibyte types... the pointer is not aligned. Use + * get_unaligned((type *)iterator.this_arg) to dereference + * iterator.this_arg for type "type" safely on all arches. + */ + +EXPORT +int ieee80211_radiotap_iterator_next(struct ieee80211_radiotap_iterator *iterator) { + while (1) { + int hit = 0; + int pad, align, size, subns; + uint32_t oui; + + /* if no more EXT bits, that's it */ + if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT && !(iterator->_bitmap_shifter & 1)) + return -ENOENT; + + if (!(iterator->_bitmap_shifter & 1)) + goto next_entry; /* arg not present */ + + /* get alignment/size of data */ + switch (iterator->_arg_index % 32) { + case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: + case IEEE80211_RADIOTAP_EXT: + align = 1; + size = 0; + break; + case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: + align = 2; + size = 6; + break; + default: +#ifdef RADIOTAP_SUPPORT_OVERRIDES + if (find_override(iterator, &align, &size)) { + /* all set */ + } else +#endif + if (!iterator->current_namespace || + iterator->_arg_index >= iterator->current_namespace->n_bits) { + if (iterator->current_namespace == &radiotap_ns) + return -ENOENT; + align = 0; + } else { + align = iterator->current_namespace->align_size[iterator->_arg_index].align; + size = iterator->current_namespace->align_size[iterator->_arg_index].size; + } + if (!align) { + /* skip all subsequent data */ + iterator->_arg = iterator->_next_ns_data; + /* give up on this namespace */ + iterator->current_namespace = NULL; + goto next_entry; + } + break; + } + + /* + * arg is present, account for alignment padding + * + * Note that these alignments are relative to the start + * of the radiotap header. There is no guarantee + * that the radiotap header itself is aligned on any + * kind of boundary. + * + * The above is why get_unaligned() is used to dereference + * multibyte elements from the radiotap area. + */ + + pad = ((unsigned long) iterator->_arg - (unsigned long) iterator->_rtheader) & (align - 1); + + if (pad) + iterator->_arg += align - pad; + + if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) { + int vnslen; + + if ((unsigned long) iterator->_arg + size - (unsigned long) iterator->_rtheader > + (unsigned long) iterator->_max_length) + return -EINVAL; + + oui = (*iterator->_arg << 16) | (*(iterator->_arg + 1) << 8) | *(iterator->_arg + 2); + subns = *(iterator->_arg + 3); + + find_ns(iterator, oui, subns); + + vnslen = get_unaligned_le16(iterator->_arg + 4); + iterator->_next_ns_data = iterator->_arg + size + vnslen; + if (!iterator->current_namespace) + size += vnslen; + } + + /* + * this is what we will return to user, but we need to + * move on first so next call has something fresh to test + */ + iterator->this_arg_index = iterator->_arg_index; + iterator->this_arg = iterator->_arg; + iterator->this_arg_size = size; + + /* internally move on the size of this arg */ + iterator->_arg += size; + + /* + * check for insanity where we are given a bitmap that + * claims to have more arg content than the length of the + * radiotap section. We will normally end up equalling this + * max_length on the last arg, never exceeding it. + */ + + if ((unsigned long) iterator->_arg - (unsigned long) iterator->_rtheader > + (unsigned long) iterator->_max_length) + return -EINVAL; + + /* these special ones are valid in each bitmap word */ + switch (iterator->_arg_index % 32) { + case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: + iterator->_reset_on_ext = 1; + + iterator->is_radiotap_ns = 0; + /* + * If parser didn't register this vendor + * namespace with us, allow it to show it + * as 'raw. Do do that, set argument index + * to vendor namespace. + */ + iterator->this_arg_index = IEEE80211_RADIOTAP_VENDOR_NAMESPACE; + if (!iterator->current_namespace) + hit = 1; + goto next_entry; + case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: + iterator->_reset_on_ext = 1; + iterator->current_namespace = &radiotap_ns; + iterator->is_radiotap_ns = 1; + goto next_entry; + case IEEE80211_RADIOTAP_EXT: + /* + * bit 31 was set, there is more + * -- move to next u32 bitmap + */ + iterator->_bitmap_shifter = get_unaligned_le32(iterator->_next_bitmap); + iterator->_next_bitmap++; + if (iterator->_reset_on_ext) + iterator->_arg_index = 0; + else + iterator->_arg_index++; + iterator->_reset_on_ext = 0; + break; + default: + /* we've got a hit! */ + hit = 1; + next_entry: + iterator->_bitmap_shifter >>= 1; + iterator->_arg_index++; + } + + /* if we found a valid arg earlier, return it now */ + if (hit) + return 0; + } +} diff --git a/src/libwifi/core/radiotap/radiotap.h b/src/libwifi/core/radiotap/radiotap.h new file mode 100644 index 0000000..cd6dd57 --- /dev/null +++ b/src/libwifi/core/radiotap/radiotap.h @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2017 Intel Deutschland GmbH + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef __RADIOTAP_H +#define __RADIOTAP_H + +#if defined(__APPLE__) +#include +#define bswap_16 OSSwapInt16 +#define bswap_32 OSSwapInt32 +#define bswap_64 OSSwapInt64 +#include +#ifndef le16toh +#define le16toh(x) OSSwapLittleToHostInt16(x) +#endif +#ifndef le32toh +#define le32toh(x) OSSwapLittleToHostInt32(x) +#endif +#ifndef le64toh +#define le64toh(x) OSSwapLittleToHostInt64(x) +#endif +#endif + +#include + +/** + * struct ieee82011_radiotap_header - base radiotap header + */ +struct ieee80211_radiotap_header { + /** + * @it_version: radiotap version, always 0 + */ + uint8_t it_version; + + /** + * @it_pad: padding (or alignment) + */ + uint8_t it_pad; + + /** + * @it_len: overall radiotap header length + */ + uint16_t it_len; + + /** + * @it_present: (first) present word + */ + uint32_t it_present; +} __attribute__((__packed__)); + +/* version is always 0 */ +#define PKTHDR_RADIOTAP_VERSION 0 + +extern const struct ieee80211_radiotap_namespace radiotap_ns; + +/* see the radiotap website for the descriptions */ +enum ieee80211_radiotap_presence { + IEEE80211_RADIOTAP_TSFT = 0, + IEEE80211_RADIOTAP_FLAGS = 1, + IEEE80211_RADIOTAP_RATE = 2, + IEEE80211_RADIOTAP_CHANNEL = 3, + IEEE80211_RADIOTAP_FHSS = 4, + IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, + IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, + IEEE80211_RADIOTAP_LOCK_QUALITY = 7, + IEEE80211_RADIOTAP_TX_ATTENUATION = 8, + IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, + IEEE80211_RADIOTAP_DBM_TX_POWER = 10, + IEEE80211_RADIOTAP_ANTENNA = 11, + IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, + IEEE80211_RADIOTAP_DB_ANTNOISE = 13, + IEEE80211_RADIOTAP_RX_FLAGS = 14, + IEEE80211_RADIOTAP_TX_FLAGS = 15, + IEEE80211_RADIOTAP_RTS_RETRIES = 16, + IEEE80211_RADIOTAP_DATA_RETRIES = 17, + /* 18 is XChannel, but it's not defined yet */ + IEEE80211_RADIOTAP_MCS = 19, + IEEE80211_RADIOTAP_AMPDU_STATUS = 20, + IEEE80211_RADIOTAP_VHT = 21, + IEEE80211_RADIOTAP_TIMESTAMP = 22, + + /* valid in every it_present bitmap, even vendor namespaces */ + IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29, + IEEE80211_RADIOTAP_VENDOR_NAMESPACE = 30, + IEEE80211_RADIOTAP_EXT = 31 +}; + +/* for IEEE80211_RADIOTAP_FLAGS */ +enum ieee80211_radiotap_flags { + IEEE80211_RADIOTAP_F_CFP = 0x01, + IEEE80211_RADIOTAP_F_SHORTPRE = 0x02, + IEEE80211_RADIOTAP_F_WEP = 0x04, + IEEE80211_RADIOTAP_F_FRAG = 0x08, + IEEE80211_RADIOTAP_F_FCS = 0x10, + IEEE80211_RADIOTAP_F_DATAPAD = 0x20, + IEEE80211_RADIOTAP_F_BADFCS = 0x40, +}; + +/* for IEEE80211_RADIOTAP_CHANNEL */ +enum ieee80211_radiotap_channel_flags { + IEEE80211_CHAN_CCK = 0x0020, + IEEE80211_CHAN_OFDM = 0x0040, + IEEE80211_CHAN_2GHZ = 0x0080, + IEEE80211_CHAN_5GHZ = 0x0100, + IEEE80211_CHAN_DYN = 0x0400, + IEEE80211_CHAN_HALF = 0x4000, + IEEE80211_CHAN_QUARTER = 0x8000, +}; + +/* for IEEE80211_RADIOTAP_RX_FLAGS */ +enum ieee80211_radiotap_rx_flags { + IEEE80211_RADIOTAP_F_RX_BADPLCP = 0x0002, +}; + +/* for IEEE80211_RADIOTAP_TX_FLAGS */ +enum ieee80211_radiotap_tx_flags { + IEEE80211_RADIOTAP_F_TX_FAIL = 0x0001, + IEEE80211_RADIOTAP_F_TX_CTS = 0x0002, + IEEE80211_RADIOTAP_F_TX_RTS = 0x0004, + IEEE80211_RADIOTAP_F_TX_NOACK = 0x0008, +}; + +/* for IEEE80211_RADIOTAP_MCS "have" flags */ +enum ieee80211_radiotap_mcs_have { + IEEE80211_RADIOTAP_MCS_HAVE_BW = 0x01, + IEEE80211_RADIOTAP_MCS_HAVE_MCS = 0x02, + IEEE80211_RADIOTAP_MCS_HAVE_GI = 0x04, + IEEE80211_RADIOTAP_MCS_HAVE_FMT = 0x08, + IEEE80211_RADIOTAP_MCS_HAVE_FEC = 0x10, + IEEE80211_RADIOTAP_MCS_HAVE_STBC = 0x20, +}; + +enum ieee80211_radiotap_mcs_flags { + IEEE80211_RADIOTAP_MCS_BW_MASK = 0x03, + IEEE80211_RADIOTAP_MCS_BW_20 = 0, + IEEE80211_RADIOTAP_MCS_BW_40 = 1, + IEEE80211_RADIOTAP_MCS_BW_20L = 2, + IEEE80211_RADIOTAP_MCS_BW_20U = 3, + + IEEE80211_RADIOTAP_MCS_SGI = 0x04, + IEEE80211_RADIOTAP_MCS_FMT_GF = 0x08, + IEEE80211_RADIOTAP_MCS_FEC_LDPC = 0x10, + IEEE80211_RADIOTAP_MCS_STBC_MASK = 0x60, + IEEE80211_RADIOTAP_MCS_STBC_1 = 1, + IEEE80211_RADIOTAP_MCS_STBC_2 = 2, + IEEE80211_RADIOTAP_MCS_STBC_3 = 3, + IEEE80211_RADIOTAP_MCS_STBC_SHIFT = 5, +}; + +/* for IEEE80211_RADIOTAP_AMPDU_STATUS */ +enum ieee80211_radiotap_ampdu_flags { + IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN = 0x0001, + IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN = 0x0002, + IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN = 0x0004, + IEEE80211_RADIOTAP_AMPDU_IS_LAST = 0x0008, + IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR = 0x0010, + IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN = 0x0020, +}; + +/* for IEEE80211_RADIOTAP_VHT */ +enum ieee80211_radiotap_vht_known { + IEEE80211_RADIOTAP_VHT_KNOWN_STBC = 0x0001, + IEEE80211_RADIOTAP_VHT_KNOWN_TXOP_PS_NA = 0x0002, + IEEE80211_RADIOTAP_VHT_KNOWN_GI = 0x0004, + IEEE80211_RADIOTAP_VHT_KNOWN_SGI_NSYM_DIS = 0x0008, + IEEE80211_RADIOTAP_VHT_KNOWN_LDPC_EXTRA_OFDM_SYM = 0x0010, + IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED = 0x0020, + IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH = 0x0040, + IEEE80211_RADIOTAP_VHT_KNOWN_GROUP_ID = 0x0080, + IEEE80211_RADIOTAP_VHT_KNOWN_PARTIAL_AID = 0x0100, +}; + +enum ieee80211_radiotap_vht_flags { + IEEE80211_RADIOTAP_VHT_FLAG_STBC = 0x01, + IEEE80211_RADIOTAP_VHT_FLAG_TXOP_PS_NA = 0x02, + IEEE80211_RADIOTAP_VHT_FLAG_SGI = 0x04, + IEEE80211_RADIOTAP_VHT_FLAG_SGI_NSYM_M10_9 = 0x08, + IEEE80211_RADIOTAP_VHT_FLAG_LDPC_EXTRA_OFDM_SYM = 0x10, + IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED = 0x20, +}; + +enum ieee80211_radiotap_vht_coding { + IEEE80211_RADIOTAP_CODING_LDPC_USER0 = 0x01, + IEEE80211_RADIOTAP_CODING_LDPC_USER1 = 0x02, + IEEE80211_RADIOTAP_CODING_LDPC_USER2 = 0x04, + IEEE80211_RADIOTAP_CODING_LDPC_USER3 = 0x08, +}; + +/* for IEEE80211_RADIOTAP_TIMESTAMP */ +enum ieee80211_radiotap_timestamp_unit_spos { + IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MASK = 0x000F, + IEEE80211_RADIOTAP_TIMESTAMP_UNIT_MS = 0x0000, + IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US = 0x0001, + IEEE80211_RADIOTAP_TIMESTAMP_UNIT_NS = 0x0003, + IEEE80211_RADIOTAP_TIMESTAMP_SPOS_MASK = 0x00F0, + IEEE80211_RADIOTAP_TIMESTAMP_SPOS_BEGIN_MDPU = 0x0000, + IEEE80211_RADIOTAP_TIMESTAMP_SPOS_PLCP_SIG_ACQ = 0x0010, + IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_PPDU = 0x0020, + IEEE80211_RADIOTAP_TIMESTAMP_SPOS_EO_MPDU = 0x0030, + IEEE80211_RADIOTAP_TIMESTAMP_SPOS_UNKNOWN = 0x00F0, +}; + +enum ieee80211_radiotap_timestamp_flags { + IEEE80211_RADIOTAP_TIMESTAMP_FLAG_64BIT = 0x00, + IEEE80211_RADIOTAP_TIMESTAMP_FLAG_32BIT = 0x01, + IEEE80211_RADIOTAP_TIMESTAMP_FLAG_ACCURACY = 0x02, +}; + +#endif /* __RADIOTAP_H */ diff --git a/src/libwifi/core/radiotap/radiotap_iter.h b/src/libwifi/core/radiotap/radiotap_iter.h new file mode 100644 index 0000000..5495a64 --- /dev/null +++ b/src/libwifi/core/radiotap/radiotap_iter.h @@ -0,0 +1,101 @@ +#ifndef __RADIOTAP_ITER_H +#define __RADIOTAP_ITER_H + +#include "platform.h" +#include "radiotap.h" +#include + +/* Radiotap header iteration + * implemented in radiotap.c + */ + +struct radiotap_override { + uint8_t field; + uint8_t align : 4, size : 4; +}; + +struct radiotap_align_size { + uint8_t align : 4, size : 4; +}; + +struct ieee80211_radiotap_namespace { + const struct radiotap_align_size *align_size; + int n_bits; + uint32_t oui; + uint8_t subns; +}; + +struct ieee80211_radiotap_vendor_namespaces { + const struct ieee80211_radiotap_namespace *ns; + int n_ns; +}; + +/** + * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args + * @this_arg_index: index of current arg, valid after each successful call + * to ieee80211_radiotap_iterator_next() + * @this_arg: pointer to current radiotap arg; it is valid after each + * call to ieee80211_radiotap_iterator_next() but also after + * ieee80211_radiotap_iterator_init() where it will point to + * the beginning of the actual data portion + * @this_arg_size: length of the current arg, for convenience + * @current_namespace: pointer to the current namespace definition + * (or internally %NULL if the current namespace is unknown) + * @is_radiotap_ns: indicates whether the current namespace is the default + * radiotap namespace or not + * + * @overrides: override standard radiotap fields + * @n_overrides: number of overrides + * + * @_rtheader: pointer to the radiotap header we are walking through + * @_max_length: length of radiotap header in cpu byte ordering + * @_arg_index: next argument index + * @_arg: next argument pointer + * @_next_bitmap: internal pointer to next present u32 + * @_bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present + * @_vns: vendor namespace definitions + * @_next_ns_data: beginning of the next namespace's data + * @_reset_on_ext: internal; reset the arg index to 0 when going to the + * next bitmap word + * + * Describes the radiotap parser state. Fields prefixed with an underscore + * must not be used by users of the parser, only by the parser internally. + */ + +struct ieee80211_radiotap_iterator { + struct ieee80211_radiotap_header *_rtheader; + const struct ieee80211_radiotap_vendor_namespaces *_vns; + const struct ieee80211_radiotap_namespace *current_namespace; + + unsigned char *_arg, *_next_ns_data; + uint32_t *_next_bitmap; + + unsigned char *this_arg; + const struct radiotap_override *overrides; /* Only for RADIOTAP_SUPPORT_OVERRIDES */ + int n_overrides; /* Only for RADIOTAP_SUPPORT_OVERRIDES */ + int this_arg_index; + int this_arg_size; + + int is_radiotap_ns; + + int _max_length; + int _arg_index; + uint32_t _bitmap_shifter; + int _reset_on_ext; +}; + +#ifdef __cplusplus +#define CALLING_CONVENTION "C" +#else +#define CALLING_CONVENTION +#endif + +IMPORT extern CALLING_CONVENTION int +ieee80211_radiotap_iterator_init(struct ieee80211_radiotap_iterator *iterator, + struct ieee80211_radiotap_header *radiotap_header, int max_length, + const struct ieee80211_radiotap_vendor_namespaces *vns); + +IMPORT extern CALLING_CONVENTION int +ieee80211_radiotap_iterator_next(struct ieee80211_radiotap_iterator *iterator); + +#endif /* __RADIOTAP_ITER_H */ diff --git a/src/libwifi/gen/control/cts.c b/src/libwifi/gen/control/cts.c new file mode 100644 index 0000000..f0e4df8 --- /dev/null +++ b/src/libwifi/gen/control/cts.c @@ -0,0 +1,30 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cts.h" + +#include + +int libwifi_create_cts(struct libwifi_cts *cts, const unsigned char receiver[6], uint16_t duration) { + memset(cts, 0, sizeof(struct libwifi_cts)); + + cts->frame_header.frame_control.type = TYPE_CONTROL; + cts->frame_header.frame_control.subtype = SUBTYPE_CTS; + cts->frame_header.duration = duration; + + memcpy(cts->receiver_addr, receiver, 6); + + return 0; +} diff --git a/src/libwifi/gen/control/cts.h b/src/libwifi/gen/control/cts.h new file mode 100644 index 0000000..bd31d33 --- /dev/null +++ b/src/libwifi/gen/control/cts.h @@ -0,0 +1,30 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_GEN_CTS_H +#define LIBWIFI_GEN_CTS_H + +#include "../../core/frame/control/cts.h" + +/** + * Create a CTS Control frame + * + * @param cts A fresh libwifi_cts struct + * @param receiver The receiver MAC address + * @param duration The duration of the clear-to-send + */ +int libwifi_create_cts(struct libwifi_cts *cts, const unsigned char receiver[6], uint16_t duration); + +#endif /* LIBWIFI_GEN_CTS_H */ diff --git a/src/libwifi/gen/control/rts.c b/src/libwifi/gen/control/rts.c new file mode 100644 index 0000000..e1710f9 --- /dev/null +++ b/src/libwifi/gen/control/rts.c @@ -0,0 +1,32 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rts.h" + +#include + +int libwifi_create_rts(struct libwifi_rts *rts, const unsigned char transmitter[6], + const unsigned char receiver[6], uint16_t duration) { + memset(rts, 0, sizeof(struct libwifi_rts)); + + rts->frame_header.frame_control.type = TYPE_CONTROL; + rts->frame_header.frame_control.subtype = SUBTYPE_RTS; + rts->frame_header.duration = duration; + + memcpy(rts->transmitter_addr, transmitter, 6); + memcpy(rts->receiver_addr, receiver, 6); + + return 0; +} diff --git a/src/libwifi/gen/control/rts.h b/src/libwifi/gen/control/rts.h new file mode 100644 index 0000000..4ad0bae --- /dev/null +++ b/src/libwifi/gen/control/rts.h @@ -0,0 +1,32 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_GEN_RTS_H +#define LIBWIFI_GEN_RTS_H + +#include "../../core/frame/control/rts.h" + +/** + * Create a RTS Control frame + * + * @param rts A fresh libwifi_rts struct + * @param transmitter The transmitter MAC address + * @param receiver The receiver MAC address + * @param duration The duration of the clear-to-send + */ +int libwifi_create_rts(struct libwifi_rts *rts, const unsigned char transmitter[6], + const unsigned char receiver[6], uint16_t duration); + +#endif /* LIBWIFI_GEN_RTS_H */ diff --git a/src/libwifi/gen/management/action.c b/src/libwifi/gen/management/action.c new file mode 100644 index 0000000..04d7a5f --- /dev/null +++ b/src/libwifi/gen/management/action.c @@ -0,0 +1,110 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "action.h" + +#include +#include +#include + +size_t libwifi_add_action_detail(struct libwifi_action_detail *detail, const unsigned char *data, + size_t data_len) { + if (detail->detail_length != 0) { + detail->detail = realloc(detail->detail, data_len); + } else { + detail->detail = malloc(data_len); + } + + if (detail->detail == NULL) { + return -EINVAL; + } + + detail->detail_length = data_len; + + memcpy(detail->detail, data, data_len); + detail->detail_length = data_len; + + return detail->detail_length; +} + +void libwifi_free_action_detail(struct libwifi_action_detail *detail) { + if (detail->detail_length != 0) { + free(detail->detail); + detail->detail_length = 0; + } +} + +int libwifi_create_action(struct libwifi_action *action, const unsigned char receiver[6], + const unsigned char transmitter[6], uint8_t category) { + memset(action, 0, sizeof(struct libwifi_action)); + + action->frame_header.frame_control.type = TYPE_MANAGEMENT; + action->frame_header.frame_control.subtype = SUBTYPE_ACTION; + memcpy(&action->frame_header.addr1, receiver, 6); + memcpy(&action->frame_header.addr2, transmitter, 6); + memcpy(&action->frame_header.addr3, transmitter, 6); + + action->frame_header.seq_control.sequence_number = (rand() % 4096); + + action->fixed_parameters.category = category; + + return 0; +} + +int libwifi_create_action_no_ack(struct libwifi_action *action, const unsigned char receiver[6], + const unsigned char transmitter[6], uint8_t category) { + memset(action, 0, sizeof(struct libwifi_action)); + + action->frame_header.frame_control.type = TYPE_MANAGEMENT; + action->frame_header.frame_control.subtype = SUBTYPE_ACTION_NOACK; + memcpy(&action->frame_header.addr1, receiver, 6); + memcpy(&action->frame_header.addr2, transmitter, 6); + memcpy(&action->frame_header.addr3, transmitter, 6); + + action->frame_header.seq_control.sequence_number = (rand() % 4096); + + action->fixed_parameters.category = category; + + return 0; +} + +size_t libwifi_get_action_length(struct libwifi_action *action) { + return sizeof(struct libwifi_mgmt_unordered_frame_header) + sizeof(action->fixed_parameters.category) + + action->fixed_parameters.details.detail_length; +} + +size_t libwifi_dump_action(struct libwifi_action *action, unsigned char *buf, size_t buf_len) { + size_t action_len = libwifi_get_action_length(action); + if (action_len > buf_len) { + return -EINVAL; + } + + size_t offset = 0; + + memcpy(buf + offset, &action->frame_header, sizeof(struct libwifi_mgmt_unordered_frame_header)); + offset += sizeof(struct libwifi_mgmt_unordered_frame_header); + + memcpy(buf + offset, &action->fixed_parameters.category, sizeof(action->fixed_parameters.category)); + offset += sizeof(action->fixed_parameters.category); + memcpy(buf + offset, action->fixed_parameters.details.detail, + action->fixed_parameters.details.detail_length); + offset += action->fixed_parameters.details.detail_length; + + return action_len; +} + +void libwifi_free_action(struct libwifi_action *action) { + free(action->fixed_parameters.details.detail); +} diff --git a/src/libwifi/gen/management/action.h b/src/libwifi/gen/management/action.h new file mode 100644 index 0000000..ae1b5cc --- /dev/null +++ b/src/libwifi/gen/management/action.h @@ -0,0 +1,80 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_GEN_ACTION_H +#define LIBWIFI_GEN_ACTION_H + +#include "../../core/frame/management/action.h" +#include + +/** + * Create a detail for an action frame by supplying raw data and it's length. + * New data can be added to an existing libwifi_action_detail. + * + * @param detail A libwifi_action_detail struct + * @param data Raw data to be added to the libwifi_action_detail + * @param data_len Length of the raw data + * @return Length of the action + */ +size_t libwifi_add_action_detail(struct libwifi_action_detail *detail, const unsigned char *data, + size_t data_len); + +/** + * Free all memory in a given libwifi_action_detail. + * + * @param detail A used libwifi_action_detail struct + */ +void libwifi_free_action_detail(struct libwifi_action_detail *detail); + +/** + * Create a new action frame with a specified action and category. + * + * @param action A new libwifi_action struct + * @param receiver The receiver MAC address + * @param transmitter The transmitter MAC address + * @param category The action frame category + * @return zero on success + */ +int libwifi_create_action(struct libwifi_action *action, const unsigned char receiver[6], + const unsigned char transmitter[6], uint8_t category); +int libwifi_create_action_no_ack(struct libwifi_action *action, const unsigned char receiver[6], + const unsigned char transmitter[6], uint8_t category); + +/** + * Get the length of a given libwifi_action + * + * @param action A used libwifi_action struct + * @return The length of the given libwifi_action + */ +size_t libwifi_get_action_length(struct libwifi_action *action); + +/** + * Dump a given libwifi_action to a raw buffer + * + * @param action A used libwifi_action struct + * @param buf A buffer receiver + * @param buf_len The length of the given buf + * @return Bytes written to the buf + */ +size_t libwifi_dump_action(struct libwifi_action *action, unsigned char *buf, size_t buf_len); + +/** + * Free data associated to a given libwifi_action + * + * @param action A used libwifi_action struct + */ +void libwifi_free_action(struct libwifi_action *action); + +#endif /* LIBWIFI_GEN_ACTION_H */ diff --git a/src/libwifi/gen/management/assoc_request.c b/src/libwifi/gen/management/assoc_request.c new file mode 100644 index 0000000..8ba3585 --- /dev/null +++ b/src/libwifi/gen/management/assoc_request.c @@ -0,0 +1,85 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "assoc_request.h" +#include "common.h" + +#include +#include +#include + +/** + * The length of an association request frame is the sum of the header length, the fixed parameters length, + * and the tagged parameters length. + */ +size_t libwifi_get_assoc_req_length(struct libwifi_assoc_req *assoc_req) { + return sizeof(assoc_req->frame_header) + sizeof(struct libwifi_assoc_req_fixed_parameters) + + assoc_req->tags.length; +} + +/** + * The generated association request frame is made with sane defaults defined in common.h. + * Two tagged parameters are also added to the association request: SSID and Channel. + */ +int libwifi_create_assoc_req(struct libwifi_assoc_req *assoc_req, const unsigned char receiver[6], + const unsigned char transmitter[6], const char *ssid, uint8_t channel) { + memset(assoc_req, 0, sizeof(struct libwifi_assoc_req)); + + assoc_req->frame_header.frame_control.type = TYPE_MANAGEMENT; + assoc_req->frame_header.frame_control.subtype = SUBTYPE_ASSOC_REQ; + memcpy(&assoc_req->frame_header.addr1, receiver, 6); + memcpy(&assoc_req->frame_header.addr2, transmitter, 6); + memcpy(&assoc_req->frame_header.addr3, receiver, 6); + assoc_req->frame_header.seq_control.sequence_number = (rand() % 4096); + + assoc_req->fixed_parameters.capabilities_information = BYTESWAP16(LIBWIFI_DEFAULT_AP_CAPABS); + assoc_req->fixed_parameters.listen_interval = BYTESWAP16(LIBWIFI_DEFAULT_LISTEN_INTERVAL); + + libwifi_quick_add_tag(&assoc_req->tags, TAG_SSID, (const unsigned char *) ssid, strlen(ssid)); + libwifi_quick_add_tag(&assoc_req->tags, TAG_DS_PARAMETER, (const unsigned char *) &channel, 1); + + return 0; +} + +/** + * Copy a libwifi_assoc_req into a regular unsigned char buffer. This is useful when injecting generated + * libwifi frames. + */ +size_t libwifi_dump_assoc_req(struct libwifi_assoc_req *assoc_req, unsigned char *buf, size_t buf_len) { + size_t assoc_req_len = libwifi_get_assoc_req_length(assoc_req); + if (assoc_req_len > buf_len) { + return -EINVAL; + } + + size_t offset = 0; + memcpy(buf + offset, &assoc_req->frame_header, sizeof(struct libwifi_mgmt_unordered_frame_header)); + offset += sizeof(struct libwifi_mgmt_unordered_frame_header); + + memcpy(buf + offset, &assoc_req->fixed_parameters, sizeof(struct libwifi_assoc_req_fixed_parameters)); + offset += sizeof(struct libwifi_assoc_req_fixed_parameters); + + memcpy(buf + offset, assoc_req->tags.parameters, assoc_req->tags.length); + offset += assoc_req->tags.length; + + return assoc_req_len; +} + +/** + * Because the tagged parameters memory is managed inside of the library, the library must + * be the one to free it, too. + */ +void libwifi_free_assoc_req(struct libwifi_assoc_req *assoc_req) { + free(assoc_req->tags.parameters); +} diff --git a/src/libwifi/gen/management/assoc_request.h b/src/libwifi/gen/management/assoc_request.h new file mode 100644 index 0000000..85cbd3b --- /dev/null +++ b/src/libwifi/gen/management/assoc_request.h @@ -0,0 +1,39 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_GEN_ASSOCREQUEST_H +#define LIBWIFI_GEN_ASSOCREQUEST_H + +#include "../../core/frame/frame.h" +#include "../../core/frame/management/assoc_request.h" +#include "../../core/frame/management/common.h" + +/** + * Create a new association request + * + * @param assoc_req A new libwifi_assoc_req struct + * @param receiver The receiver MAC address + * @param transmitter The transmitter MAC address + * @param ssid The desired BSS SSID + * @param channel The desired channel + * @param zero on success + */ +int libwifi_create_assoc_req(struct libwifi_assoc_req *assoc_req, const unsigned char receiver[6], + const unsigned char transmitter[6], const char *ssid, uint8_t channel); +size_t libwifi_get_assoc_req_length(struct libwifi_assoc_req *assoc_req); +size_t libwifi_dump_assoc_req(struct libwifi_assoc_req *assoc_req, unsigned char *buf, size_t buf_len); +void libwifi_free_assoc_req(struct libwifi_assoc_req *assoc_req); + +#endif /* LIBWIFI_GEN_ASSOCREQUEST_H */ diff --git a/src/libwifi/gen/management/assoc_response.c b/src/libwifi/gen/management/assoc_response.c new file mode 100644 index 0000000..be00511 --- /dev/null +++ b/src/libwifi/gen/management/assoc_response.c @@ -0,0 +1,106 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "assoc_response.h" +#include "../../core/frame/tag.h" +#include "../../core/frame/tag_iterator.h" +#include "../../core/misc/byteswap.h" +#include "../../core/misc/epoch.h" +#include "../../core/misc/types.h" +#include "common.h" + +#include +#include +#include +#include +#include +#include + +/** + * The length of an association response frame is the sum of the header length, the fixed parameters length, + * and the tagged parameters length. + */ +size_t libwifi_get_assoc_resp_length(struct libwifi_assoc_resp *assoc_resp) { + return sizeof(struct libwifi_mgmt_unordered_frame_header) + + sizeof(struct libwifi_assoc_resp_fixed_parameters) + assoc_resp->tags.length; +} + +/** + * Simple helper function to set the channel of an association response by removing and re-adding the + * DS tagged parameter. + */ +void libwifi_set_assoc_resp_channel(struct libwifi_assoc_resp *assoc_resp, uint8_t channel) { + if (assoc_resp->tags.length != 0) { + libwifi_remove_tag(&assoc_resp->tags, TAG_DS_PARAMETER); + } + + const unsigned char *chan = (const unsigned char *) &channel; + + libwifi_quick_add_tag(&assoc_resp->tags, TAG_DS_PARAMETER, chan, 1); +} + +/** + * The generated association response frame is made with sane defaults defined in common.h and core/types.h. + * Two tagged parameters are also added to the association response: Channel and Supported Rates. + */ +void libwifi_create_assoc_resp(struct libwifi_assoc_resp *assoc_resp, const unsigned char receiver[6], + const unsigned char transmitter[6], uint8_t channel) { + memset(assoc_resp, 0, sizeof(struct libwifi_assoc_resp)); + + assoc_resp->frame_header.frame_control.type = TYPE_MANAGEMENT; + assoc_resp->frame_header.frame_control.subtype = SUBTYPE_ASSOC_RESP; + memcpy(&assoc_resp->frame_header.addr1, receiver, 6); + memcpy(&assoc_resp->frame_header.addr2, transmitter, 6); + + assoc_resp->fixed_parameters.capabilities_information = BYTESWAP16(LIBWIFI_DEFAULT_AP_CAPABS); + assoc_resp->fixed_parameters.status_code = STATUS_SUCCESS; + assoc_resp->fixed_parameters.association_id = rand() % 4096; + + libwifi_set_assoc_resp_channel(assoc_resp, channel); + + const unsigned char supported_rates[] = LIBWIFI_DEFAULT_SUPP_RATES; + libwifi_quick_add_tag(&assoc_resp->tags, TAG_SUPP_RATES, supported_rates, sizeof(supported_rates) - 1); +} + +/** + * Copy a libwifi_assoc_resp into a regular unsigned char buffer. This is useful when injecting generated + * libwifi frames. + */ +size_t libwifi_dump_assoc_resp(struct libwifi_assoc_resp *assoc_resp, unsigned char *buf, size_t buf_len) { + size_t assoc_resp_len = libwifi_get_assoc_resp_length(assoc_resp); + if (assoc_resp_len > buf_len) { + return -EINVAL; + } + + size_t offset = 0; + memcpy(buf + offset, &assoc_resp->frame_header, sizeof(struct libwifi_mgmt_unordered_frame_header)); + offset += sizeof(struct libwifi_mgmt_unordered_frame_header); + + memcpy(buf + offset, &assoc_resp->fixed_parameters, sizeof(struct libwifi_assoc_resp_fixed_parameters)); + offset += sizeof(struct libwifi_assoc_resp_fixed_parameters); + + memcpy(buf + offset, assoc_resp->tags.parameters, assoc_resp->tags.length); + offset += assoc_resp->tags.length; + + return assoc_resp_len; +} + +/** + * Because the tagged parameters memory is managed inside of the library, the library must + * be the one to free it, too. + */ +void libwifi_free_assoc_resp(struct libwifi_assoc_resp *assoc_resp) { + free(assoc_resp->tags.parameters); +} diff --git a/src/libwifi/gen/management/assoc_response.h b/src/libwifi/gen/management/assoc_response.h new file mode 100644 index 0000000..9162d1c --- /dev/null +++ b/src/libwifi/gen/management/assoc_response.h @@ -0,0 +1,69 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_GEN_ASSOCRESP_H +#define LIBWIFI_GEN_ASSOCRESP_H + +#include "../../core/frame/management/assoc_response.h" + +/** + * Set the channel of a libwifi_assoc_resp. + * + * @param assoc_resp A libwifi_assoc_resp + * @param channel The new channel + */ +void libwifi_set_assoc_resp_channel(struct libwifi_assoc_resp *assoc_resp, uint8_t channel); + +/** + * Calculate the length of a given libwifi_assoc_resp + * + * @param assoc_resp A libwifi_assoc_resp + * @return The length of the given assoc_resp + */ +size_t libwifi_get_assoc_resp_length(struct libwifi_assoc_resp *assoc_resp); + +/** + * Generate a populated libwifi assoc_resp. + * + * A generated libwifi assoc_resp can be "dumped" into a buffer for packet injection + * via the libwifi_dump_assoc_resp. + * + * @param assoc_resp A libwifi_assoc_resp + * @param receiver The receiver MAC address, aka address 1 + * @param transmitter The source MAC address, aka address 2 + * @param channel The desired channel of the assoc_resp + * + */ +void libwifi_create_assoc_resp(struct libwifi_assoc_resp *assoc_resp, const unsigned char receiver[6], + const unsigned char transmitter[6], uint8_t channel); + +/** + * Dump a libwifi_assoc_resp into a raw format for packet injection. + * + * @param assoc_resp A libwifi_assoc_resp + * @param buf The output buffer for the frame data + * @param buf_len The length of the output buffer + * @return The length of the dumped assoc_resp + */ +size_t libwifi_dump_assoc_resp(struct libwifi_assoc_resp *assoc_resp, unsigned char *buf, size_t buf_len); + +/** + * Free any memory claimed by a libwifi_assoc_resp back to the system. + * + * @param assoc_resp A libwifi_assoc_resp + */ +void libwifi_free_assoc_resp(struct libwifi_assoc_resp *assoc_resp); + +#endif /* LIBWIFI_GEN_ASSOCRESP_H */ diff --git a/src/libwifi/gen/management/atim.c b/src/libwifi/gen/management/atim.c new file mode 100644 index 0000000..960a2de --- /dev/null +++ b/src/libwifi/gen/management/atim.c @@ -0,0 +1,35 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "atim.h" + +#include +#include + +int libwifi_create_atim(struct libwifi_atim *atim, const unsigned char transmitter[6], + const unsigned char receiver[6], const unsigned char bssid[6]) { + memset(atim, 0, sizeof(struct libwifi_atim)); + + atim->frame_header.frame_control.type = TYPE_MANAGEMENT; + atim->frame_header.frame_control.subtype = SUBTYPE_ATIM; + memcpy(&atim->frame_header.addr1, transmitter, 6); + memcpy(&atim->frame_header.addr2, receiver, 6); + memcpy(&atim->frame_header.addr3, bssid, 6); + atim->frame_header.frame_control.flags.power_mgmt = 1; + atim->frame_header.duration = (rand() % 4096); + atim->frame_header.seq_control.sequence_number = (rand() % 4096); + + return 0; +} diff --git a/src/libwifi/gen/management/atim.h b/src/libwifi/gen/management/atim.h new file mode 100644 index 0000000..d9a306a --- /dev/null +++ b/src/libwifi/gen/management/atim.h @@ -0,0 +1,24 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_GEN_ATIM_H +#define LIBWIFI_GEN_ATIM_H + +#include "../../core/frame/management/atim.h" + +int libwifi_create_atim(struct libwifi_atim *atim, const unsigned char transmitter[6], + const unsigned char receiver[6], const unsigned char bssid[6]); + +#endif /* LIBWIFI_GEN_ATIM_H */ diff --git a/src/libwifi/gen/management/authentication.c b/src/libwifi/gen/management/authentication.c new file mode 100644 index 0000000..7fcaa22 --- /dev/null +++ b/src/libwifi/gen/management/authentication.c @@ -0,0 +1,81 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "authentication.h" +#include "../../core/misc/byteswap.h" + +#include +#include +#include + +/** + * The length of an authentication frame is the sum of the header length, the fixed parameters length, and the + * tagged parameters length. + */ +size_t libwifi_get_auth_length(struct libwifi_auth *auth) { + return sizeof(struct libwifi_mgmt_unordered_frame_header) + sizeof(struct libwifi_auth_fixed_parameters) + + auth->tags.length; +} + +/** + * The generated authentication frame is made with sane defaults defined in common.h. + */ +void libwifi_create_auth(struct libwifi_auth *auth, const unsigned char receiver[6], + const unsigned char transmitter[6], uint16_t algorithm_number, + uint16_t transaction_sequence, uint16_t status_code) { + memset(auth, 0, sizeof(struct libwifi_auth)); + + auth->frame_header.frame_control.type = TYPE_MANAGEMENT; + auth->frame_header.frame_control.subtype = SUBTYPE_AUTH; + memcpy(&auth->frame_header.addr1, receiver, 6); + memcpy(&auth->frame_header.addr2, transmitter, 6); + memcpy(&auth->frame_header.addr3, transmitter, 6); + auth->frame_header.seq_control.sequence_number = (rand() % 4096); + + auth->fixed_parameters.algorithm_number = algorithm_number; + auth->fixed_parameters.transaction_sequence = transaction_sequence; + auth->fixed_parameters.status_code = status_code; +} + +/** + * Copy a libwifi_auth into a regular unsigned char buffer. This is useful when injecting generated + * libwifi frames. + */ +size_t libwifi_dump_auth(struct libwifi_auth *auth, unsigned char *buf, size_t buf_len) { + size_t auth_len = libwifi_get_auth_length(auth); + if (auth_len > buf_len) { + return -EINVAL; + } + + size_t offset = 0; + memcpy(buf + offset, &auth->frame_header, sizeof(struct libwifi_mgmt_unordered_frame_header)); + offset += sizeof(struct libwifi_mgmt_unordered_frame_header); + + memcpy(buf + offset, &auth->fixed_parameters, sizeof(struct libwifi_auth_fixed_parameters)); + offset += sizeof(struct libwifi_auth_fixed_parameters); + + memcpy(buf + offset, auth->tags.parameters, auth->tags.length); + offset += auth->tags.length; + + return auth_len; +} + +/** + * Because the tagged parameters memory is managed inside of the library, the library must + * be the one to free it, too. + */ +void libwifi_free_auth(struct libwifi_auth *auth) { + free(auth->tags.parameters); +} diff --git a/src/libwifi/gen/management/authentication.h b/src/libwifi/gen/management/authentication.h new file mode 100644 index 0000000..4328f95 --- /dev/null +++ b/src/libwifi/gen/management/authentication.h @@ -0,0 +1,64 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_GEN_AUTH_H +#define LIBWIFI_GEN_AUTH_H + +#include + +#include "../../core/frame/management/authentication.h" + +/** + * Calculate the length of a given libwifi_auth + * + * @param auth A libwifi_auth + * @return The length of the given auth + */ +size_t libwifi_get_auth_length(struct libwifi_auth *auth); + +/** + * Generate a populated libwifi auth. + * + * A generated libwifi auth can be "dumped" into a buffer for packet injection + * via the libwifi_dump_auth. + * + * @param auth A libwifi_auth + * @param receiver The receiver MAC address, aka address 1 + * @param transmitter The source MAC address, aka address 2 + * @param algorithm_number Algorithm type to use + * + */ +void libwifi_create_auth(struct libwifi_auth *auth, const unsigned char receiver[6], + const unsigned char transmitter[6], uint16_t algorithm_number, + uint16_t transaction_sequence, uint16_t status_code); + +/** + * Dump a libwifi_auth into a raw format for packet injection. + * + * @param auth A libwifi_auth + * @param buf The output buffer for the frame data + * @param buf_len The length of the output buffer + * @return The length of the dumped auth + */ +size_t libwifi_dump_auth(struct libwifi_auth *auth, unsigned char *buf, size_t buf_len); + +/** + * Free any memory claimed by a libwifi_auth back to the system. + * + * @param auth A libwifi_auth + */ +void libwifi_free_auth(struct libwifi_auth *auth); + +#endif /* LIBWIFI_GEN_AUTH_H */ diff --git a/src/libwifi/gen/management/beacon.c b/src/libwifi/gen/management/beacon.c new file mode 100644 index 0000000..4eb394a --- /dev/null +++ b/src/libwifi/gen/management/beacon.c @@ -0,0 +1,117 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "beacon.h" +#include "../../core/frame/tag.h" +#include "../../core/frame/tag_iterator.h" +#include "../../core/misc/byteswap.h" +#include "../../core/misc/epoch.h" +#include "common.h" + +#include +#include +#include +#include +#include +#include + +/** + * The length of a beacon frame is the sum of the header length, the fixed parameters length, and the tagged + * parameters length. + */ +size_t libwifi_get_beacon_length(struct libwifi_beacon *beacon) { + return sizeof(struct libwifi_mgmt_unordered_frame_header) + + sizeof(struct libwifi_beacon_fixed_parameters) + beacon->tags.length; +} + +/** + * Simple helper to set the beacon SSID tag by removing it and then adding it back with the new value. + */ +void libwifi_set_beacon_ssid(struct libwifi_beacon *beacon, const char *ssid) { + if (beacon->tags.length != 0) { + libwifi_remove_tag(&beacon->tags, TAG_SSID); + } + + libwifi_quick_add_tag(&beacon->tags, TAG_SSID, (void *) ssid, strlen(ssid)); +} + +/** + * Simple helper to set the beacon DS tag by removing it and then adding it back with the new value. + */ +void libwifi_set_beacon_channel(struct libwifi_beacon *beacon, uint8_t channel) { + if (beacon->tags.length != 0) { + libwifi_remove_tag(&beacon->tags, TAG_DS_PARAMETER); + } + + const unsigned char *chan = (const unsigned char *) &channel; + + libwifi_quick_add_tag(&beacon->tags, TAG_DS_PARAMETER, chan, 1); +} + +/** + * The generated beacon frame is made with sane defaults defined in common.h. + * Three tagged parameters are also added to the beacon: SSID, Channel and Supported Rates. + */ +void libwifi_create_beacon(struct libwifi_beacon *beacon, const unsigned char receiver[6], + const unsigned char transmitter[6], const char *ssid, uint8_t channel) { + memset(beacon, 0, sizeof(struct libwifi_beacon)); + + beacon->frame_header.frame_control.type = TYPE_MANAGEMENT; + beacon->frame_header.frame_control.subtype = SUBTYPE_BEACON; + memcpy(&beacon->frame_header.addr1, receiver, 6); + memcpy(&beacon->frame_header.addr2, transmitter, 6); + beacon->frame_header.seq_control.sequence_number = (rand() % 4096); + + beacon->fixed_parameters.timestamp = BYTESWAP64(libwifi_get_epoch()); + beacon->fixed_parameters.beacon_interval = BYTESWAP16(LIBWIFI_DEFAULT_BEACON_INTERVAL); + beacon->fixed_parameters.capabilities_information = BYTESWAP16(LIBWIFI_DEFAULT_AP_CAPABS); + + libwifi_set_beacon_ssid(beacon, ssid); + libwifi_set_beacon_channel(beacon, channel); + + const unsigned char supported_rates[] = LIBWIFI_DEFAULT_SUPP_RATES; + libwifi_quick_add_tag(&beacon->tags, TAG_SUPP_RATES, supported_rates, sizeof(supported_rates) - 1); +} + +/** + * Copy a libwifi_beacon into a regular unsigned char buffer. This is useful when injecting generated + * libwifi frames. + */ +size_t libwifi_dump_beacon(struct libwifi_beacon *beacon, unsigned char *buf, size_t buf_len) { + size_t beacon_len = libwifi_get_beacon_length(beacon); + if (beacon_len > buf_len) { + return -EINVAL; + } + + size_t offset = 0; + memcpy(buf + offset, &beacon->frame_header, sizeof(struct libwifi_mgmt_unordered_frame_header)); + offset += sizeof(struct libwifi_mgmt_unordered_frame_header); + + memcpy(buf + offset, &beacon->fixed_parameters, sizeof(struct libwifi_beacon_fixed_parameters)); + offset += sizeof(struct libwifi_beacon_fixed_parameters); + + memcpy(buf + offset, beacon->tags.parameters, beacon->tags.length); + offset += beacon->tags.length; + + return beacon_len; +} + +/** + * Because the tagged parameters memory is managed inside of the library, the library must + * be the one to free it, too. + */ +void libwifi_free_beacon(struct libwifi_beacon *beacon) { + free(beacon->tags.parameters); +} diff --git a/src/libwifi/gen/management/beacon.h b/src/libwifi/gen/management/beacon.h new file mode 100644 index 0000000..3da342b --- /dev/null +++ b/src/libwifi/gen/management/beacon.h @@ -0,0 +1,78 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_GEN_BEACON_H +#define LIBWIFI_GEN_BEACON_H + +#include "../../core/frame/management/beacon.h" + +/** + * Set the SSID of a struct libwifi_beacon. + * + * @param beacon A struct libwifi_beacon + * @param ssid The new SSID + */ +void libwifi_set_beacon_ssid(struct libwifi_beacon *beacon, const char *ssid); + +/** + * Set the channel of a struct libwifi_beacon. + * + * @param beacon A struct libwifi_beacon + * @param channel The new channel + */ +void libwifi_set_beacon_channel(struct libwifi_beacon *beacon, uint8_t channel); + +/** + * Calculate the length of a given struct libwifi_beacon + * + * @param beacon A struct libwifi_beacon + * @return The length of the given beacon + */ +size_t libwifi_get_beacon_length(struct libwifi_beacon *beacon); + +/** + * Generate a populated libwifi beacon. + * + * A generated libwifi beacon can be "dumped" into a buffer for packet injection + * via the libwifi_dump_beacon. + * + * @param beacon A struct libwifi_beacon + * @param receiver The receiver MAC address, aka address 1 + * @param transmitter The source MAC address, aka address 2 + * @param ssid The SSID of the beacon. Maximum length is 32 characters + * @param channel The desired channel of the beacon + * + */ +void libwifi_create_beacon(struct libwifi_beacon *beacon, const unsigned char receiver[6], + const unsigned char transmitter[6], const char *ssid, uint8_t channel); + +/** + * Dump a struct libwifi_beacon into a raw format for packet injection. + * + * @param beacon A struct libwifi_beacon + * @param buf The output buffer for the frame data + * @param buf_len The length of the output buffer + * @return The length of the dumped beacon + */ +size_t libwifi_dump_beacon(struct libwifi_beacon *beacon, unsigned char *buf, size_t buf_len); + +/** + * Free any memory claimed by a struct libwifi_beacon back to the system. + * + * @param beacon A struct libwifi_beacon + */ +void libwifi_free_beacon(struct libwifi_beacon *beacon); + +#endif /* LIBWIFI_GEN_BEACON_H */ diff --git a/src/libwifi/gen/management/common.h b/src/libwifi/gen/management/common.h new file mode 100644 index 0000000..ec3b744 --- /dev/null +++ b/src/libwifi/gen/management/common.h @@ -0,0 +1,54 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_GEN_COMMON_H +#define LIBWIFI_GEN_COMMON_H + +/** + * A sane default for an AP-side capabilities information field. + * + * 0x0001 = Transmitter is an AP + */ +#define LIBWIFI_DEFAULT_AP_CAPABS 0x0001 + +/** + * A sane default for an STA-side capabilities information field. + * + * 0x0000 = None + */ +#define LIBWIFI_DEFAULT_STA_CAPABS 0x0000 + +/** + * A sane default for the listen_interval field. + * + * 0x0001 = 1 Beacon Interval + */ +#define LIBWIFI_DEFAULT_LISTEN_INTERVAL 0x0001 + +/** + * A sane default for a beacon_interval field. + * + * 0x0064 = 0.1024 Seconds + */ +#define LIBWIFI_DEFAULT_BEACON_INTERVAL 0x0064 + +/** + * A sane default for the supported rates frame field. + * + * 1, 2, 5.5, 11, 18, 24, 36, 54 Mbit/s + */ +#define LIBWIFI_DEFAULT_SUPP_RATES "\x82\x84\x8b\x96\x24\x30\x48\x6c" + +#endif /* LIBWIFI_GEN_COMMON_H */ diff --git a/src/libwifi/gen/management/deauthentication.c b/src/libwifi/gen/management/deauthentication.c new file mode 100644 index 0000000..14f2c26 --- /dev/null +++ b/src/libwifi/gen/management/deauthentication.c @@ -0,0 +1,82 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "deauthentication.h" +#include "../../core/misc/byteswap.h" + +#include +#include +#include + +/** + * The length of a deauth frame is the sum of the header length, the fixed parameters length, and the tagged + * parameters length. + */ +size_t libwifi_get_deauth_length(struct libwifi_deauth *deauth) { + return sizeof(struct libwifi_mgmt_unordered_frame_header) + + sizeof(struct libwifi_deauth_fixed_parameters) + deauth->tags.length; +} + +/** + * The generated deauthentication frame contains only the supplied receiver, transmitter and reason_code by + * default. + */ +int libwifi_create_deauth(struct libwifi_deauth *deauth, const unsigned char receiver[6], + const unsigned char transmitter[6], uint16_t reason_code) { + memset(deauth, 0, sizeof(struct libwifi_deauth)); + + deauth->frame_header.frame_control.type = TYPE_MANAGEMENT; + deauth->frame_header.frame_control.subtype = SUBTYPE_DEAUTH; + memcpy(&deauth->frame_header.addr1, receiver, 6); + memcpy(&deauth->frame_header.addr2, transmitter, 6); + memcpy(&deauth->frame_header.addr3, transmitter, 6); + + deauth->frame_header.seq_control.sequence_number = (rand() % 4096); + + memcpy(&deauth->fixed_parameters.reason_code, &reason_code, sizeof(reason_code)); + + return 0; +} + +/** + * Copy a libwifi_deauth into a regular unsigned char buffer. This is useful when injecting generated + * libwifi frames. + */ +size_t libwifi_dump_deauth(struct libwifi_deauth *deauth, unsigned char *buf, size_t buf_len) { + size_t deauth_len = libwifi_get_deauth_length(deauth); + if (deauth_len > buf_len) { + return -EINVAL; + } + + size_t offset = 0; + memcpy(buf + offset, &deauth->frame_header, sizeof(struct libwifi_mgmt_unordered_frame_header)); + offset += sizeof(struct libwifi_mgmt_unordered_frame_header); + + memcpy(buf + offset, &deauth->fixed_parameters, sizeof(struct libwifi_deauth_fixed_parameters)); + offset += sizeof(struct libwifi_deauth_fixed_parameters); + + memcpy(buf + offset, deauth->tags.parameters, deauth->tags.length); + offset += deauth->tags.length; + + return deauth_len; +} + +/** + * Because the tagged parameters memory is managed inside of the library, the library must + * be the one to free it, too. + */ +void libwifi_free_deauth(struct libwifi_deauth *deauth) { + free(deauth->tags.parameters); +} diff --git a/src/libwifi/gen/management/deauthentication.h b/src/libwifi/gen/management/deauthentication.h new file mode 100644 index 0000000..902241d --- /dev/null +++ b/src/libwifi/gen/management/deauthentication.h @@ -0,0 +1,63 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_GEN_DEAUTH_H +#define LIBWIFI_GEN_DEAUTH_H + +#include + +#include "../../core/frame/management/deauthentication.h" + +/** + * Calculate the length of a given libwifi_deauth + * + * @param deauth A libwifi_deauth + * @return The length of the given deauth + */ +size_t libwifi_get_deauth_length(struct libwifi_deauth *deauth); + +/** + * Generate a populated libwifi deauth. + * + * A generated libwifi deauth can be "dumped" into a buffer for packet injection + * via the libwifi_dump_deauth. + * + * @param deauth A libwifi_deauth + * @param receiver The receiver MAC address, aka address 1 + * @param transmitter The source MAC address, aka address 2 + * @param reason_code The deauth reason code + * + */ +int libwifi_create_deauth(struct libwifi_deauth *deauth, const unsigned char receiver[6], + const unsigned char transmitter[6], uint16_t reason_code); + +/** + * Dump a libwifi_deauth into a raw format for packet injection. + * + * @param deauth A libwifi_deauth + * @param buf The output buffer for the frame data + * @param buf_len The length of the output buffer + * @return The length of the dumped deauth + */ +size_t libwifi_dump_deauth(struct libwifi_deauth *deauth, unsigned char *buf, size_t buf_len); + +/** + * Free any memory claimed by a libwifi_deauth back to the system. + * + * @param deauth A libwifi_deauth + */ +void libwifi_free_deauth(struct libwifi_deauth *deauth); + +#endif /* LIBWIFI_GEN_DEAUTH_H */ diff --git a/src/libwifi/gen/management/disassociation.c b/src/libwifi/gen/management/disassociation.c new file mode 100644 index 0000000..a885efd --- /dev/null +++ b/src/libwifi/gen/management/disassociation.c @@ -0,0 +1,80 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "disassociation.h" +#include "../../core/misc/byteswap.h" + +#include +#include +#include + +/** + * The length of a disassoc frame is the sum of the header length, the fixed parameters length, and the tagged + * parameters length. + */ +size_t libwifi_get_disassoc_length(struct libwifi_disassoc *disassoc) { + return sizeof(struct libwifi_mgmt_unordered_frame_header) + + sizeof(struct libwifi_disassoc_fixed_parameters) + disassoc->tags.length; +} + +/** + * The generated disassociation frame contains only the supplied receiver, transmitter and reason_code by + * default. + */ +void libwifi_create_disassoc(struct libwifi_disassoc *disassoc, const unsigned char receiver[6], + const unsigned char transmitter[6], uint16_t reason_code) { + memset(disassoc, 0, sizeof(struct libwifi_disassoc)); + + disassoc->frame_header.frame_control.type = TYPE_MANAGEMENT; + disassoc->frame_header.frame_control.subtype = SUBTYPE_DISASSOC; + memcpy(&disassoc->frame_header.addr1, receiver, 6); + memcpy(&disassoc->frame_header.addr2, transmitter, 6); + memcpy(&disassoc->frame_header.addr3, transmitter, 6); + + disassoc->frame_header.seq_control.sequence_number = (rand() % 4096); + + memcpy(&disassoc->fixed_parameters.reason_code, &reason_code, sizeof(reason_code)); +} + +/** + * Copy a libwifi_disassoc into a regular unsigned char buffer. This is useful when injecting generated + * libwifi frames. + */ +size_t libwifi_dump_disassoc(struct libwifi_disassoc *disassoc, unsigned char *buf, size_t buf_len) { + size_t disassoc_len = libwifi_get_disassoc_length(disassoc); + if (disassoc_len > buf_len) { + return -EINVAL; + } + + size_t offset = 0; + memcpy(buf + offset, &disassoc->frame_header, sizeof(struct libwifi_mgmt_unordered_frame_header)); + offset += sizeof(struct libwifi_mgmt_unordered_frame_header); + + memcpy(buf + offset, &disassoc->fixed_parameters, sizeof(struct libwifi_disassoc_fixed_parameters)); + offset += sizeof(struct libwifi_disassoc_fixed_parameters); + + memcpy(buf + offset, disassoc->tags.parameters, disassoc->tags.length); + offset += disassoc->tags.length; + + return disassoc_len; +} + +/** + * Because the tagged parameters memory is managed inside of the library, the library must + * be the one to free it, too. + */ +void libwifi_free_disassoc(struct libwifi_disassoc *disassoc) { + free(disassoc->tags.parameters); +} diff --git a/src/libwifi/gen/management/disassociation.h b/src/libwifi/gen/management/disassociation.h new file mode 100644 index 0000000..fada9f0 --- /dev/null +++ b/src/libwifi/gen/management/disassociation.h @@ -0,0 +1,63 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_GEN_DISASSOC_H +#define LIBWIFI_GEN_DISASSOC_H + +#include + +#include "../../core/frame/management/disassociation.h" + +/** + * Calculate the length of a given libwifi_disassoc + * + * @param disassoc A libwifi_disassoc + * @return The length of the given disassoc + */ +size_t libwifi_get_disassoc_length(struct libwifi_disassoc *disassoc); + +/** + * Generate a populated libwifi disassoc. + * + * A generated libwifi disassoc can be "dumped" into a buffer for packet injection + * via the libwifi_dump_disassoc. + * + * @param disassoc A libwifi_disassoc + * @param receiver The receiver MAC address, aka address 1 + * @param transmitter The source MAC address, aka address 2 + * @param reason_code The disassoc reason code + * + */ +void libwifi_create_disassoc(struct libwifi_disassoc *disassoc, const unsigned char receiver[6], + const unsigned char transmitter[6], uint16_t reason_code); + +/** + * Dump a libwifi_disassoc into a raw format for packet injection. + * + * @param disassoc A libwifi_disassoc + * @param buf The output buffer for the frame data + * @param buf_len The length of the output buffer + * @return The length of the dumped disassoc + */ +size_t libwifi_dump_disassoc(struct libwifi_disassoc *disassoc, unsigned char *buf, size_t buf_len); + +/** + * Free any memory claimed by a libwifi_disassoc back to the system. + * + * @param disassoc A libwifi_disassoc + */ +void libwifi_free_disassoc(struct libwifi_disassoc *disassoc); + +#endif /* LIBWIFI_GEN_DISASSOC_H */ diff --git a/src/libwifi/gen/management/probe_request.c b/src/libwifi/gen/management/probe_request.c new file mode 100644 index 0000000..7c5b99e --- /dev/null +++ b/src/libwifi/gen/management/probe_request.c @@ -0,0 +1,76 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "probe_request.h" +#include "../../core/misc/byteswap.h" + +#include +#include +#include + +/** + * The length of a probe request frame is the sum of the header length plus the tagged parameters length. + */ +size_t libwifi_get_probe_req_length(struct libwifi_probe_req *probe_req) { + return sizeof(struct libwifi_mgmt_unordered_frame_header) + probe_req->tags.length; +} + +/** + * The generated probe request frame is made with sane defaults defined in common.h. + * Two tagged parameters are also added to the beacon: SSID and Channel. + */ +void libwifi_create_probe_req(struct libwifi_probe_req *probe_req, const unsigned char receiver[6], + const unsigned char transmitter[6], const unsigned char bssid[6], + const char *ssid, uint8_t channel) { + memset(probe_req, 0, sizeof(struct libwifi_probe_req)); + + probe_req->frame_header.frame_control.type = TYPE_MANAGEMENT; + probe_req->frame_header.frame_control.subtype = SUBTYPE_PROBE_REQ; + memcpy(&probe_req->frame_header.addr1, receiver, 6); + memcpy(&probe_req->frame_header.addr2, transmitter, 6); + memcpy(&probe_req->frame_header.addr3, bssid, 6); + probe_req->frame_header.seq_control.sequence_number = (rand() % 4096); + + libwifi_quick_add_tag(&probe_req->tags, TAG_SSID, (const unsigned char *) ssid, strlen(ssid)); + libwifi_quick_add_tag(&probe_req->tags, TAG_DS_PARAMETER, (const unsigned char *) &channel, 1); +} + +/** + * Copy a libwifi_probe_req into a regular unsigned char buffer. This is useful when injecting generated + * libwifi frames. + */ +size_t libwifi_dump_probe_req(struct libwifi_probe_req *probe_req, unsigned char *buf, size_t buf_len) { + size_t probe_req_len = libwifi_get_probe_req_length(probe_req); + if (probe_req_len > buf_len) { + return -EINVAL; + } + + size_t offset = 0; + memcpy(buf + offset, &probe_req->frame_header, sizeof(struct libwifi_mgmt_unordered_frame_header)); + offset += sizeof(struct libwifi_mgmt_unordered_frame_header); + + memcpy(buf + offset, probe_req->tags.parameters, probe_req->tags.length); + offset += probe_req->tags.length; + + return probe_req_len; +} + +/** + * Because the tagged parameters memory is managed inside of the library, the library must + * be the one to free it, too. + */ +void libwifi_free_probe_req(struct libwifi_probe_req *probe_req) { + free(probe_req->tags.parameters); +} diff --git a/src/libwifi/gen/management/probe_request.h b/src/libwifi/gen/management/probe_request.h new file mode 100644 index 0000000..f98b70a --- /dev/null +++ b/src/libwifi/gen/management/probe_request.h @@ -0,0 +1,64 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_GEN_PROBEREQ_H +#define LIBWIFI_GEN_PROBEREQ_H + +#include + +#include "../../core/frame/management/probe_request.h" + +/** + * Calculate the length of a given libwifi_probe_req + * + * @param probe_req A libwifi_probe_req + * @return The length of the given probe_req + */ +size_t libwifi_get_probe_req_length(struct libwifi_probe_req *probe_req); + +/** + * Generate a populated libwifi probe_req. + * + * A generated libwifi probe_req can be "dumped" into a buffer for packet injection + * via the libwifi_dump_probe_req. + * + * @param probe_req A libwifi_probe_req + * @param receiver The receiver MAC address, aka address 1 + * @param transmitter The source MAC address, aka address 2 + * @param reason_code The probe_req reason code + * + */ +void libwifi_create_probe_req(struct libwifi_probe_req *probe_req, const unsigned char receiver[6], + const unsigned char transmitter[6], const unsigned char bssid[6], + const char *ssid, uint8_t channel); + +/** + * Dump a libwifi_probe_req into a raw format for packet injection. + * + * @param probe_req A libwifi_probe_req + * @param buf The output buffer for the frame data + * @param buf_len The length of the output buffer + * @return The length of the dumped probe_req + */ +size_t libwifi_dump_probe_req(struct libwifi_probe_req *probe_req, unsigned char *buf, size_t buf_len); + +/** + * Free any memory claimed by a libwifi_probe_req back to the system. + * + * @param probe_req A libwifi_probe_req + */ +void libwifi_free_probe_req(struct libwifi_probe_req *probe_req); + +#endif /* LIBWIFI_GEN_PROBEREQ_H */ diff --git a/src/libwifi/gen/management/probe_response.c b/src/libwifi/gen/management/probe_response.c new file mode 100644 index 0000000..403a8bc --- /dev/null +++ b/src/libwifi/gen/management/probe_response.c @@ -0,0 +1,118 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "probe_response.h" +#include "../../core/frame/tag.h" +#include "../../core/frame/tag_iterator.h" +#include "../../core/misc/byteswap.h" +#include "../../core/misc/epoch.h" +#include "common.h" + +#include +#include +#include +#include +#include +#include + +/** + * The length of a probe response frame is the sum of the header length, the fixed parameters length, and the + * tagged parameters length. + */ +size_t libwifi_get_probe_resp_length(struct libwifi_probe_resp *probe_resp) { + return sizeof(struct libwifi_mgmt_unordered_frame_header) + + sizeof(struct libwifi_probe_resp_fixed_parameters) + probe_resp->tags.length; +} + +/** + * Simple helper to set the probe response SSID tag by removing it and then adding it back with the new value. + */ +void libwifi_set_probe_resp_ssid(struct libwifi_probe_resp *probe_resp, const char *ssid) { + if (probe_resp->tags.length != 0) { + libwifi_remove_tag(&probe_resp->tags, TAG_SSID); + } + + libwifi_quick_add_tag(&probe_resp->tags, TAG_SSID, (void *) ssid, strlen(ssid)); +} + +/** + * Simple helper to set the probe response DS tag by removing it and then adding it back with the new value. + */ +void libwifi_set_probe_resp_channel(struct libwifi_probe_resp *probe_resp, uint8_t channel) { + if (probe_resp->tags.length != 0) { + libwifi_remove_tag(&probe_resp->tags, TAG_DS_PARAMETER); + } + + const unsigned char *chan = (const unsigned char *) &channel; + + libwifi_quick_add_tag(&probe_resp->tags, TAG_DS_PARAMETER, chan, 1); +} + +/** + * The generated probe response frame is made with sane defaults defined in common.h. + * Three tagged parameters are also added to the probe response: SSID, Channel and Supported Rates. + */ +void libwifi_create_probe_resp(struct libwifi_probe_resp *probe_resp, const unsigned char receiver[6], + const unsigned char transmitter[6], const char *ssid, uint8_t channel) { + memset(probe_resp, 0, sizeof(struct libwifi_probe_resp)); + + probe_resp->frame_header.frame_control.type = TYPE_MANAGEMENT; + probe_resp->frame_header.frame_control.subtype = SUBTYPE_PROBE_RESP; + memcpy(&probe_resp->frame_header.addr1, receiver, 6); + memcpy(&probe_resp->frame_header.addr2, transmitter, 6); + + probe_resp->frame_header.seq_control.sequence_number = (rand() % 4096); + probe_resp->fixed_parameters.timestamp = BYTESWAP64(libwifi_get_epoch()); + uint16_t probe_resp_interval = 50 + (rand() % 100); + probe_resp->fixed_parameters.probe_resp_interval = BYTESWAP16(probe_resp_interval); + probe_resp->fixed_parameters.capabilities_information = BYTESWAP16(LIBWIFI_DEFAULT_AP_CAPABS); + + libwifi_set_probe_resp_ssid(probe_resp, ssid); + libwifi_set_probe_resp_channel(probe_resp, channel); + + const unsigned char supported_rates[] = LIBWIFI_DEFAULT_SUPP_RATES; + libwifi_quick_add_tag(&probe_resp->tags, TAG_SUPP_RATES, supported_rates, sizeof(supported_rates) - 1); +} + +/** + * Copy a libwifi_probe_resp into a regular unsigned char buffer. This is useful when injecting generated + * libwifi frames. + */ +size_t libwifi_dump_probe_resp(struct libwifi_probe_resp *probe_resp, unsigned char *buf, size_t buf_len) { + size_t probe_resp_len = libwifi_get_probe_resp_length(probe_resp); + if (probe_resp_len > buf_len) { + return -EINVAL; + } + + size_t offset = 0; + memcpy(buf + offset, &probe_resp->frame_header, sizeof(struct libwifi_mgmt_unordered_frame_header)); + offset += sizeof(struct libwifi_mgmt_unordered_frame_header); + + memcpy(buf + offset, &probe_resp->fixed_parameters, sizeof(struct libwifi_probe_resp_fixed_parameters)); + offset += sizeof(struct libwifi_probe_resp_fixed_parameters); + + memcpy(buf + offset, probe_resp->tags.parameters, probe_resp->tags.length); + offset += probe_resp->tags.length; + + return probe_resp_len; +} + +/** + * Because the tagged parameters memory is managed inside of the library, the library must + * be the one to free it, too. + */ +void libwifi_free_probe_resp(struct libwifi_probe_resp *probe_resp) { + free(probe_resp->tags.parameters); +} diff --git a/src/libwifi/gen/management/probe_response.h b/src/libwifi/gen/management/probe_response.h new file mode 100644 index 0000000..56243ee --- /dev/null +++ b/src/libwifi/gen/management/probe_response.h @@ -0,0 +1,78 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_GEN_PROBERESP_H +#define LIBWIFI_GEN_PROBERESP_H + +#include "../../core/frame/management/probe_response.h" + +/** + * Set the SSID of a libwifi_probe_resp. + * + * @param probe_resp A libwifi_probe_resp + * @param ssid The new SSID + */ +void libwifi_set_probe_resp_ssid(struct libwifi_probe_resp *probe_resp, const char *ssid); + +/** + * Set the channel of a libwifi_probe_resp. + * + * @param probe_resp A libwifi_probe_resp + * @param channel The new channel + */ +void libwifi_set_probe_resp_channel(struct libwifi_probe_resp *probe_resp, uint8_t channel); + +/** + * Calculate the length of a given libwifi_probe_resp + * + * @param probe_resp A libwifi_probe_resp + * @return The length of the given probe_resp + */ +size_t libwifi_get_probe_resp_length(struct libwifi_probe_resp *probe_resp); + +/** + * Generate a populated libwifi probe_resp. + * + * A generated libwifi probe_resp can be "dumped" into a buffer for packet injection + * via the libwifi_dump_probe_resp. + * + * @param probe_resp A libwifi_probe_resp + * @param receiver The receiver MAC address, aka address 1 + * @param transmitter The source MAC address, aka address 2 + * @param ssid The SSID of the probe_resp. Maximum length is 32 characters + * @param channel The desired channel of the probe_resp + * + */ +void libwifi_create_probe_resp(struct libwifi_probe_resp *probe_resp, const unsigned char receiver[6], + const unsigned char transmitter[6], const char *ssid, uint8_t channel); + +/** + * Dump a libwifi_probe_resp into a raw format for packet injection. + * + * @param probe_resp A libwifi_probe_resp + * @param buf The output buffer for the frame data + * @param buf_len The length of the output buffer + * @return The length of the dumped probe_resp + */ +size_t libwifi_dump_probe_resp(struct libwifi_probe_resp *probe_resp, unsigned char *buf, size_t buf_len); + +/** + * Free any memory claimed by a libwifi_probe_resp back to the system. + * + * @param probe_resp A libwifi_probe_resp + */ +void libwifi_free_probe_resp(struct libwifi_probe_resp *probe_resp); + +#endif /* LIBWIFI_GEN_PROBERESP_H */ diff --git a/src/libwifi/gen/management/reassoc_request.c b/src/libwifi/gen/management/reassoc_request.c new file mode 100644 index 0000000..f678caf --- /dev/null +++ b/src/libwifi/gen/management/reassoc_request.c @@ -0,0 +1,87 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "reassoc_request.h" +#include "common.h" + +#include +#include +#include + +/** + * The length of a reassociation request frame is the sum of the header length, the fixed parameters length, + * and the tagged parameters length. + */ +size_t libwifi_get_reassoc_req_length(struct libwifi_reassoc_req *reassoc_req) { + return sizeof(struct libwifi_mgmt_unordered_frame_header) + + sizeof(struct libwifi_reassoc_req_fixed_parameters) + reassoc_req->tags.length; +} + +/** + * The generated reassociation request frame is made with sane defaults defined in common.h. + * Two tagged parameters are also added to the reassociation frame: SSID and Channel + */ +int libwifi_create_reassoc_req(struct libwifi_reassoc_req *reassoc_req, const unsigned char receiver[6], + const unsigned char transmitter[6], const unsigned char current_ap[6], + const char *ssid, uint8_t channel) { + memset(reassoc_req, 0, sizeof(struct libwifi_reassoc_req)); + + reassoc_req->frame_header.frame_control.type = TYPE_MANAGEMENT; + reassoc_req->frame_header.frame_control.subtype = SUBTYPE_REASSOC_REQ; + memcpy(&reassoc_req->frame_header.addr1, receiver, 6); + memcpy(&reassoc_req->frame_header.addr2, transmitter, 6); + memcpy(&reassoc_req->frame_header.addr3, receiver, 6); + reassoc_req->frame_header.seq_control.sequence_number = (rand() % 4096); + + reassoc_req->fixed_parameters.capabilities_information = BYTESWAP16(LIBWIFI_DEFAULT_AP_CAPABS); + reassoc_req->fixed_parameters.listen_interval = BYTESWAP16(LIBWIFI_DEFAULT_LISTEN_INTERVAL); + memcpy(&reassoc_req->fixed_parameters.current_ap_address, current_ap, 6); + + libwifi_quick_add_tag(&reassoc_req->tags, TAG_SSID, (const unsigned char *) ssid, strlen(ssid)); + libwifi_quick_add_tag(&reassoc_req->tags, TAG_DS_PARAMETER, (const unsigned char *) &channel, 1); + + return 0; +} + +/** + * Copy a libwifi_reassoc_req into a regular unsigned char buffer. This is useful when injecting generated + * libwifi frames. + */ +size_t libwifi_dump_reassoc_req(struct libwifi_reassoc_req *reassoc_req, unsigned char *buf, size_t buf_len) { + size_t reassoc_req_len = libwifi_get_reassoc_req_length(reassoc_req); + if (reassoc_req_len > buf_len) { + return -EINVAL; + } + + size_t offset = 0; + memcpy(buf + offset, &reassoc_req->frame_header, sizeof(struct libwifi_mgmt_unordered_frame_header)); + offset += sizeof(struct libwifi_mgmt_unordered_frame_header); + + memcpy(buf + offset, &reassoc_req->fixed_parameters, sizeof(struct libwifi_reassoc_req_fixed_parameters)); + offset += sizeof(struct libwifi_reassoc_req_fixed_parameters); + + memcpy(buf + offset, reassoc_req->tags.parameters, reassoc_req->tags.length); + offset += reassoc_req->tags.length; + + return reassoc_req_len; +} + +/** + * Because the tagged parameters memory is managed inside of the library, the library must + * be the one to free it, too. + */ +void libwifi_free_reassoc_req(struct libwifi_reassoc_req *reassoc_req) { + free(reassoc_req->tags.parameters); +} diff --git a/src/libwifi/gen/management/reassoc_request.h b/src/libwifi/gen/management/reassoc_request.h new file mode 100644 index 0000000..3db971f --- /dev/null +++ b/src/libwifi/gen/management/reassoc_request.h @@ -0,0 +1,30 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_GEN_REASSOCREQUEST_H +#define LIBWIFI_GEN_REASSOCREQUEST_H + +#include "../../core/frame/frame.h" +#include "../../core/frame/management/common.h" +#include "../../core/frame/management/reassoc_request.h" + +int libwifi_create_reassoc_req(struct libwifi_reassoc_req *reassoc_req, const unsigned char receiver[6], + const unsigned char transmitter[6], const unsigned char current_ap[6], + const char *ssid, uint8_t channel); +size_t libwifi_get_reassoc_req_length(struct libwifi_reassoc_req *reassoc_req); +size_t libwifi_dump_reassoc_req(struct libwifi_reassoc_req *reassoc_req, unsigned char *buf, size_t buf_len); +void libwifi_free_reassoc_req(struct libwifi_reassoc_req *reassoc_req); + +#endif /* LIBWIFI_GEN_REASSOCREQUEST_H */ diff --git a/src/libwifi/gen/management/reassoc_response.c b/src/libwifi/gen/management/reassoc_response.c new file mode 100644 index 0000000..b9acbb6 --- /dev/null +++ b/src/libwifi/gen/management/reassoc_response.c @@ -0,0 +1,108 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "reassoc_response.h" +#include "../../core/frame/tag.h" +#include "../../core/frame/tag_iterator.h" +#include "../../core/misc/byteswap.h" +#include "../../core/misc/epoch.h" +#include "../../core/misc/types.h" +#include "common.h" + +#include +#include +#include +#include +#include +#include + +/** + * The length of a reassociation response frame is the sum of the header length, the fixed parameters length, + * and the tagged parameters length. + */ +size_t libwifi_get_reassoc_resp_length(struct libwifi_reassoc_resp *reassoc_resp) { + return sizeof(struct libwifi_mgmt_unordered_frame_header) + + sizeof(struct libwifi_reassoc_resp_fixed_parameters) + reassoc_resp->tags.length; +} + +/** + * Simple helper to set the reassociation response DS tag by removing it and then adding it back with the new + * value. + */ +void libwifi_set_reassoc_resp_channel(struct libwifi_reassoc_resp *reassoc_resp, uint8_t channel) { + if (reassoc_resp->tags.length != 0) { + libwifi_remove_tag(&reassoc_resp->tags, TAG_DS_PARAMETER); + } + + const unsigned char *chan = (const unsigned char *) &channel; + + libwifi_quick_add_tag(&reassoc_resp->tags, TAG_DS_PARAMETER, chan, 1); +} + +/** + * The generated reassoc_resp frame is made with sane defaults defined in common.h. + * Three tagged parameters are also added to the reassoc_resp: SSID, Channel and Supported Rates. + */ +void libwifi_create_reassoc_resp(struct libwifi_reassoc_resp *reassoc_resp, const unsigned char receiver[6], + const unsigned char transmitter[6], uint8_t channel) { + memset(reassoc_resp, 0, sizeof(struct libwifi_reassoc_resp)); + + reassoc_resp->frame_header.frame_control.type = TYPE_MANAGEMENT; + reassoc_resp->frame_header.frame_control.subtype = SUBTYPE_REASSOC_RESP; + memcpy(&reassoc_resp->frame_header.addr1, receiver, 6); + memcpy(&reassoc_resp->frame_header.addr2, transmitter, 6); + + reassoc_resp->fixed_parameters.capabilities_information = BYTESWAP16(LIBWIFI_DEFAULT_AP_CAPABS); + reassoc_resp->fixed_parameters.status_code = STATUS_SUCCESS; + reassoc_resp->fixed_parameters.association_id = rand() % 4096; + + libwifi_set_reassoc_resp_channel(reassoc_resp, channel); + + const unsigned char supported_rates[] = LIBWIFI_DEFAULT_SUPP_RATES; + libwifi_quick_add_tag(&reassoc_resp->tags, TAG_SUPP_RATES, supported_rates, sizeof(supported_rates) - 1); +} + +/** + * Copy a libwifi_reassoc_resp into a regular unsigned char buffer. This is useful when injecting generated + * libwifi frames. + */ +size_t libwifi_dump_reassoc_resp(struct libwifi_reassoc_resp *reassoc_resp, unsigned char *buf, + size_t buf_len) { + size_t reassoc_resp_len = libwifi_get_reassoc_resp_length(reassoc_resp); + if (reassoc_resp_len > buf_len) { + return -EINVAL; + } + + size_t offset = 0; + memcpy(buf + offset, &reassoc_resp->frame_header, sizeof(struct libwifi_mgmt_unordered_frame_header)); + offset += sizeof(struct libwifi_mgmt_unordered_frame_header); + + memcpy(buf + offset, &reassoc_resp->fixed_parameters, + sizeof(struct libwifi_reassoc_resp_fixed_parameters)); + offset += sizeof(struct libwifi_reassoc_resp_fixed_parameters); + + memcpy(buf + offset, reassoc_resp->tags.parameters, reassoc_resp->tags.length); + offset += reassoc_resp->tags.length; + + return reassoc_resp_len; +} + +/** + * Because the tagged parameters memory is managed inside of the library, the library must + * be the one to free it, too. + */ +void libwifi_free_reassoc_resp(struct libwifi_reassoc_resp *reassoc_resp) { + free(reassoc_resp->tags.parameters); +} diff --git a/src/libwifi/gen/management/reassoc_response.h b/src/libwifi/gen/management/reassoc_response.h new file mode 100644 index 0000000..f0a2da2 --- /dev/null +++ b/src/libwifi/gen/management/reassoc_response.h @@ -0,0 +1,70 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_GEN_REASSOCRESP_H +#define LIBWIFI_GEN_REASSOCRESP_H + +#include "../../core/frame/management/reassoc_response.h" + +/** + * Set the channel of a libwifi_reassoc_resp. + * + * @param reassoc_resp A libwifi_reassoc_resp + * @param channel The new channel + */ +void libwifi_set_reassoc_resp_channel(struct libwifi_reassoc_resp *reassoc_resp, uint8_t channel); + +/** + * Calculate the length of a given libwifi_reassoc_resp + * + * @param reassoc_resp A libwifi_reassoc_resp + * @return The length of the given reassoc_resp + */ +size_t libwifi_get_reassoc_resp_length(struct libwifi_reassoc_resp *reassoc_resp); + +/** + * Generate a populated libwifi reassoc_resp. + * + * A generated libwifi reassoc_resp can be "dumped" into a buffer for packet injection + * via the libwifi_dump_reassoc_resp. + * + * @param reassoc_resp A libwifi_reassoc_resp + * @param receiver The receiver MAC address, aka address 1 + * @param transmitter The source MAC address, aka address 2 + * @param channel The desired channel of the reassoc_resp + * + */ +void libwifi_create_reassoc_resp(struct libwifi_reassoc_resp *reassoc_resp, const unsigned char receiver[6], + const unsigned char transmitter[6], uint8_t channel); + +/** + * Dump a libwifi_reassoc_resp into a raw format for packet injection. + * + * @param reassoc_resp A libwifi_reassoc_resp + * @param buf The output buffer for the frame data + * @param buf_len The length of the output buffer + * @return The length of the dumped reassoc_resp + */ +size_t libwifi_dump_reassoc_resp(struct libwifi_reassoc_resp *reassoc_resp, unsigned char *buf, + size_t buf_len); + +/** + * Free any memory claimed by a libwifi_reassoc_resp back to the system. + * + * @param reassoc_resp A libwifi_reassoc_resp + */ +void libwifi_free_reassoc_resp(struct libwifi_reassoc_resp *reassoc_resp); + +#endif /* LIBWIFI_GEN_REASSOCRESP_H */ diff --git a/src/libwifi/gen/management/timing_ad.c b/src/libwifi/gen/management/timing_ad.c new file mode 100644 index 0000000..6e67a6b --- /dev/null +++ b/src/libwifi/gen/management/timing_ad.c @@ -0,0 +1,111 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common.h" +#include "timing_ad.h" +#include "../../core/frame/management/timing_ad.h" +#include "../../core/misc/epoch.h" +#include "../../core/frame/tag.h" + +#include +#include + +void libwifi_create_timing_advert(struct libwifi_timing_advert *adv, const unsigned char destination[6], + const unsigned char transmitter[6], struct libwifi_timing_advert_fields *adv_fields, + const char country[3], uint16_t max_reg_power, uint8_t max_tx_power, uint8_t tx_power_used, + uint8_t noise_floor) { + memset(adv, 0, sizeof(struct libwifi_timing_advert)); + + adv->frame_header.frame_control.type = TYPE_MANAGEMENT; + adv->frame_header.frame_control.subtype = SUBTYPE_TIME_ADV; + memcpy(&adv->frame_header.addr1, destination, 6); + memcpy(&adv->frame_header.addr2, transmitter, 6); + adv->frame_header.seq_control.sequence_number = (rand() % 4096); + + adv->fixed_parameters.timestamp = BYTESWAP64(libwifi_get_epoch()); + adv->fixed_parameters.measurement_pilot_interval = LIBWIFI_DEFAULT_BEACON_INTERVAL; + adv->fixed_parameters.beacon_interval = LIBWIFI_DEFAULT_BEACON_INTERVAL; + adv->fixed_parameters.capabilities_information = BYTESWAP16(LIBWIFI_DEFAULT_AP_CAPABS); + memcpy(adv->fixed_parameters.country, country, sizeof(adv->fixed_parameters.country)); + adv->fixed_parameters.max_reg_power = BYTESWAP16(max_reg_power); + adv->fixed_parameters.max_tx_power = max_tx_power; + adv->fixed_parameters.tx_power_used = tx_power_used; + adv->fixed_parameters.noise_floor = noise_floor; + + if (adv_fields == NULL) { + return; + } + + // Maximum element size is 17 + unsigned char element_data[17] = {0}; + size_t element_data_len = 0; + int offset = 0; + + memcpy(element_data, &adv_fields->timing_capabilities, sizeof(adv_fields->timing_capabilities)); + offset += sizeof(adv_fields->timing_capabilities); + + switch (adv_fields->timing_capabilities) { + case 1: { /* Time Value and Time Error fields present */ + memcpy(element_data + offset, &adv_fields->time_value, sizeof(adv_fields->time_value)); + offset += sizeof(adv_fields->time_value); + memcpy(element_data + offset, &adv_fields->time_error, sizeof(adv_fields->time_error)); + offset += sizeof(adv_fields->time_error); + break; + } + case 2: { /* Time Value, Time Error, and Time Update fields present */ + memcpy(element_data + offset, &adv_fields->time_value, sizeof(adv_fields->time_value)); + offset += sizeof(adv_fields->time_value); + memcpy(element_data + offset, &adv_fields->time_error, sizeof(adv_fields->time_error)); + offset += sizeof(adv_fields->time_error); + memcpy(element_data + offset, &adv_fields->time_update, sizeof(adv_fields->time_update)); + offset += sizeof(adv_fields->time_update); + } + default: + break; + } + + element_data_len = offset; + + libwifi_quick_add_tag(&adv->tags, TAG_TIME_ADVERTISEMENT, element_data, element_data_len); +} + +size_t libwifi_get_timing_advert_length(struct libwifi_timing_advert *adv) { + return sizeof(struct libwifi_mgmt_unordered_frame_header) + + sizeof(struct libwifi_timing_advert_fixed_params) + + adv->tags.length; +} + +size_t libwifi_dump_timing_advert(struct libwifi_timing_advert *adv, unsigned char *buf, size_t buf_len) { + size_t adv_len = libwifi_get_timing_advert_length(adv); + if (adv_len > buf_len) { + return -1; + } + + size_t offset = 0; + memcpy(buf + offset, &adv->frame_header, sizeof(struct libwifi_mgmt_unordered_frame_header)); + offset += sizeof(struct libwifi_mgmt_unordered_frame_header); + + memcpy(buf + offset, &adv->fixed_parameters, sizeof(struct libwifi_timing_advert_fixed_params)); + offset += sizeof(struct libwifi_timing_advert_fixed_params); + + memcpy(buf + offset, adv->tags.parameters, adv->tags.length); + offset += adv->tags.length; + + return adv_len; +} + +void libwifi_free_timing_advert(struct libwifi_timing_advert *adv) { + free(adv->tags.parameters); +} diff --git a/src/libwifi/gen/management/timing_ad.h b/src/libwifi/gen/management/timing_ad.h new file mode 100644 index 0000000..cdcb827 --- /dev/null +++ b/src/libwifi/gen/management/timing_ad.h @@ -0,0 +1,32 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_GEN_TIMINGAD_H +#define LIBWIFI_GEN_TIMINGAD_H + +#include "../../core/frame/management/timing_ad.h" + +void libwifi_create_timing_advert(struct libwifi_timing_advert *adv, const unsigned char destination[6], + const unsigned char transmitter[6], struct libwifi_timing_advert_fields *adv_fields, + const char country[3], uint16_t max_reg_power, uint8_t max_tx_power, uint8_t tx_power_used, + uint8_t noise_floor); + +size_t libwifi_get_timing_advert_length(struct libwifi_timing_advert *adv); + +size_t libwifi_dump_timing_advert(struct libwifi_timing_advert *adv, unsigned char *buf, size_t buf_len); + +void libwifi_free_timing_advert(struct libwifi_timing_advert *adv); + +#endif /* LIBWIFI_GEN_TIMINGAD_H */ diff --git a/src/libwifi/gen/misc/radiotap.c b/src/libwifi/gen/misc/radiotap.c new file mode 100644 index 0000000..cc02097 --- /dev/null +++ b/src/libwifi/gen/misc/radiotap.c @@ -0,0 +1,123 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "radiotap.h" +#include "../../core/radiotap/radiotap.h" +#include "../../core/radiotap/radiotap_iter.h" + +#include +#include +#include + +#define LIBWIFI_RADIOTAP_HEADER_LEN 8 + +size_t libwifi_create_radiotap(struct libwifi_radiotap_info *info, char *radiotap_header) { + struct ieee80211_radiotap_header rtap_hdr = {0}; + rtap_hdr.it_version = 0; + rtap_hdr.it_pad = 0; + rtap_hdr.it_present = info->present; + rtap_hdr.it_len = sizeof(struct ieee80211_radiotap_header); + + char rtap_data[LIBWIFI_MAX_RADIOTAP_LEN - LIBWIFI_RADIOTAP_HEADER_LEN] = {0}; + int offset = 0; + + uint32_t presence_bit = rtap_hdr.it_present; + for (int field = 0; field < radiotap_ns.n_bits; field++) { + if (presence_bit & 1) { + switch (field) { + case IEEE80211_RADIOTAP_CHANNEL: + memcpy(rtap_data + offset, &info->channel.freq, sizeof(info->channel.freq)); + offset += sizeof(info->channel.freq); + memcpy(rtap_data + offset, &info->channel.flags, sizeof(info->channel.flags)); + offset += sizeof(info->channel.flags); + break; + case IEEE80211_RADIOTAP_RATE: + memcpy(rtap_data + offset, &info->rate_raw, sizeof(info->rate_raw)); + offset += sizeof(info->rate_raw); + break; + case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: + memcpy(rtap_data + offset, &info->signal, sizeof(info->signal)); + offset += sizeof(info->signal); + break; + case IEEE80211_RADIOTAP_ANTENNA: + for (int i = 0; i < info->antenna_count; i++) { + memcpy(rtap_data + offset, &info->antennas->antenna_number, + sizeof(info->antennas->antenna_number)); + offset += sizeof(info->antennas->antenna_number); + memcpy(rtap_data + offset, &info->antennas->signal, sizeof(info->antennas->signal)); + offset += sizeof(info->antennas->signal); + } + break; + case IEEE80211_RADIOTAP_DBM_ANTNOISE: + break; + case IEEE80211_RADIOTAP_FLAGS: + memcpy(rtap_data + offset, &info->flags, sizeof(info->flags)); + offset += sizeof(info->flags); + break; + case IEEE80211_RADIOTAP_EXT: + memcpy(rtap_data + offset, &info->extended_flags, sizeof(info->extended_flags)); + offset += sizeof(info->extended_flags); + break; + case IEEE80211_RADIOTAP_RX_FLAGS: + memcpy(rtap_data + offset, &info->rx_flags, sizeof(info->rx_flags)); + offset += sizeof(info->rx_flags); + break; + case IEEE80211_RADIOTAP_TX_FLAGS: + memcpy(rtap_data + offset, &info->tx_flags, sizeof(info->tx_flags)); + offset += sizeof(info->tx_flags); + break; + case IEEE80211_RADIOTAP_MCS: + memcpy(rtap_data + offset, &info->mcs.known, sizeof(info->mcs.known)); + offset += sizeof(info->mcs.known); + memcpy(rtap_data + offset, &info->mcs.flags, sizeof(info->mcs.flags)); + offset += sizeof(info->mcs.flags); + memcpy(rtap_data + offset, &info->mcs.mcs, sizeof(info->mcs.mcs)); + offset += sizeof(info->mcs.mcs); + break; + case IEEE80211_RADIOTAP_DBM_TX_POWER: + memcpy(rtap_data + offset, &info->tx_power, sizeof(info->tx_power)); + offset += sizeof(info->tx_power); + break; + case IEEE80211_RADIOTAP_TIMESTAMP: + memcpy(rtap_data + offset, &info->timestamp.timestamp, sizeof(info->timestamp.timestamp)); + offset += sizeof(info->timestamp.timestamp); + memcpy(rtap_data + offset, &info->timestamp.accuracy, sizeof(info->timestamp.accuracy)); + offset += sizeof(info->timestamp.accuracy); + memcpy(rtap_data + offset, &info->timestamp.unit, sizeof(info->timestamp.unit)); + offset += sizeof(info->timestamp.unit); + memcpy(rtap_data + offset, &info->timestamp.flags, sizeof(info->timestamp.flags)); + offset += sizeof(info->timestamp.flags); + break; + case IEEE80211_RADIOTAP_RTS_RETRIES: + memcpy(rtap_data + offset, &info->rts_retries, sizeof(info->rts_retries)); + offset += sizeof(info->rts_retries); + break; + case IEEE80211_RADIOTAP_DATA_RETRIES: + memcpy(rtap_data + offset, &info->data_retries, sizeof(info->data_retries)); + offset += sizeof(info->data_retries); + break; + } + } + + presence_bit >>= 1; + } + + rtap_hdr.it_len += offset; + + memcpy(radiotap_header, &rtap_hdr, sizeof(struct ieee80211_radiotap_header)); + memcpy(radiotap_header + sizeof(struct ieee80211_radiotap_header), &rtap_data, offset); + + return rtap_hdr.it_len; +} diff --git a/src/libwifi/gen/misc/radiotap.h b/src/libwifi/gen/misc/radiotap.h new file mode 100644 index 0000000..00e2ac8 --- /dev/null +++ b/src/libwifi/gen/misc/radiotap.h @@ -0,0 +1,31 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_GEN_RADIOTAP_H +#define LIBWIFI_GEN_RADIOTAP_H + +#include "../../core/misc/radiotap.h" +#include + +/* + * Generate a customised radiotap header based on the input provided in info. + * + * @param info A libwifi_radiotap_info struct with desired radiotap data. + * @param radiotap_header Buffer to write the radiotap header into. + * @return Length of the generated radiotap header. + */ +size_t libwifi_create_radiotap(struct libwifi_radiotap_info *info, char *radiotap_header); + +#endif /* LIBWIFI_GEN_RADIOTAP_H */ diff --git a/src/libwifi/parse/data/data.c b/src/libwifi/parse/data/data.c new file mode 100644 index 0000000..74bff32 --- /dev/null +++ b/src/libwifi/parse/data/data.c @@ -0,0 +1,48 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "data.h" + +#include +#include +#include + +int libwifi_parse_data(struct libwifi_data *data, struct libwifi_frame *frame) { + if (frame->frame_control.type != TYPE_DATA) { + return -EINVAL; + } + + if (frame->flags & LIBWIFI_FLAGS_IS_QOS) { + memcpy(data->receiver, frame->header.data_qos.addr1, 6); + memcpy(data->transmitter, frame->header.data_qos.addr2, 6); + } else { + memcpy(data->receiver, frame->header.data.addr1, 6); + memcpy(data->transmitter, frame->header.data.addr2, 6); + } + + data->body_len = frame->len - frame->header_len; + + data->body = malloc(data->body_len); + if (data->body == NULL) { + return -ENOMEM; + } + memcpy(frame->body, data->body, data->body_len); + + return 0; +} + +void libwifi_free_data(struct libwifi_data *data) { + free(data->body); +} diff --git a/src/libwifi/parse/data/data.h b/src/libwifi/parse/data/data.h new file mode 100644 index 0000000..3ed3bd4 --- /dev/null +++ b/src/libwifi/parse/data/data.h @@ -0,0 +1,26 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_PARSE_DATA_H +#define LIBWIFI_PARSE_DATA_H + +#include "../../core/frame/data/data.h" +#include "../../core/frame/frame.h" + +int libwifi_parse_data(struct libwifi_data *data, struct libwifi_frame *frame); + +void libwifi_free_data(struct libwifi_data *data); + +#endif /* LIBWIFI_PARSE_DATA_H */ diff --git a/src/libwifi/parse/data/eapol.c b/src/libwifi/parse/data/eapol.c new file mode 100644 index 0000000..b8e3d18 --- /dev/null +++ b/src/libwifi/parse/data/eapol.c @@ -0,0 +1,190 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "eapol.h" +#include "../../core/frame/frame.h" +#include "../../core/misc/byteswap.h" +#include "../../core/misc/llc.h" +#include "../../core/misc/security.h" + +#include +#include +#include +#include +#include + +/** + * A libwifi_frame is deemed to be an EAPOL handshake if the following criteria is met: + * - The frame is of type TYPE_DATA, and + * - The frame contains a logical link control layer, and + * - There is enough data in the frame body to fill a libwifi_wpa_auth_data struct. + */ +int libwifi_check_wpa_handshake(struct libwifi_frame *frame) { + // WPA Handshakes are transmitted in EAPOL frames + if (frame->frame_control.type != TYPE_DATA) { + return -EINVAL; + } + + // Data frame must be at least the length of the header plus the encapsulating LLC + if (frame->len < (frame->header_len + sizeof(struct libwifi_logical_link_ctrl))) { + return -EINVAL; + } + + // Represent the LLC layer so that we can check the OUI and ensure it is correct + struct libwifi_logical_link_ctrl *llc = (struct libwifi_logical_link_ctrl *) (frame->body); + if (memcmp(llc->oui, XEROX_OUI, sizeof(llc->oui)) != 0) { + return -EINVAL; + } + + // Match the network byte-order of LLC and ensure we have a frame containing 802.1X information + if (ntohs(llc->type) != LLC_TYPE_AUTH) { + return -EINVAL; + } + + // Ensure we have enough information in the frame to fill a libwifi_wpa_auth_data struct + // This value is calculated by ensuring the frame is at least the length of the LLC layer, plus the length + // of the libwifi_wpa_auth_data struct, however, the length of an unsigned char pointer is subtracted due + // to the possibility of the frame having no WPA key data. + size_t required_data_length = + frame->header_len + (sizeof(struct libwifi_logical_link_ctrl) + + (sizeof(struct libwifi_wpa_auth_data) - sizeof(unsigned char *))); + if (frame->len < required_data_length) { + return -EINVAL; + } + + return 1; +} + +/* + * The specific EAPOL message in the supplied libwifi_frame is determined via the 802.1X key information + * field. + */ +int libwifi_check_wpa_message(struct libwifi_frame *frame) { + // Ensure we have enough information in the frame to fill a libwifi_wpa_auth_data struct + // This value is calculated by ensuring the frame is at least the length of the LLC layer, plus the length + // of the libwifi_wpa_auth_data struct, however, the length of an unsigned char pointer is subtracted due + // to the possibility of the frame having no WPA key data. + size_t required_data_length = + frame->header_len + (sizeof(struct libwifi_logical_link_ctrl) + + (sizeof(struct libwifi_wpa_auth_data) - sizeof(unsigned char *))); + if (frame->len < required_data_length) { + return HANDSHAKE_INVALID; + } + + struct libwifi_wpa_auth_data *auth_data = + (struct libwifi_wpa_auth_data *) (frame->body + sizeof(struct libwifi_logical_link_ctrl)); + switch (ntohs(auth_data->key_info.information)) { + case EAPOL_KEY_INFO_M1: + return HANDSHAKE_M1; + case EAPOL_KEY_INFO_M2: + return HANDSHAKE_M2; + case EAPOL_KEY_INFO_M3: + return HANDSHAKE_M3; + case EAPOL_KEY_INFO_M4: + return HANDSHAKE_M4; + default: + return HANDSHAKE_INVALID; + } +} + +/* + * Simple helper function to print a string depending on the EAPOL message + */ +const char *libwifi_get_wpa_message_string(struct libwifi_frame *frame) { + int message = libwifi_check_wpa_message(frame); + + switch (message) { + case HANDSHAKE_M1: + return "Message 1"; + case HANDSHAKE_M2: + return "Message 2"; + case HANDSHAKE_M3: + return "Message 3"; + case HANDSHAKE_M4: + return "Message 4"; + case HANDSHAKE_INVALID: + default: + return "Invalid"; + } +} + +/* + * The value returned here is the length of the data available _after_ the rest of the EAPOL data, + * and should be used for obtaining the EAPOL Key Data, if present. + */ +int libwifi_get_wpa_key_data_length(struct libwifi_frame *frame) { + if (libwifi_check_wpa_handshake(frame) < 0) { + return -EINVAL; + } + + struct libwifi_wpa_auth_data *auth_data = + (struct libwifi_wpa_auth_data *) (frame->body + sizeof(struct libwifi_logical_link_ctrl)); + + // Byte-swap the multi-byte length key_data_length for the host system + return ntohs(auth_data->key_info.key_data_length); +} + +/* + * Data in the supplied libwifi_frame is expected to be in network byte order. To avoid confusion, this + * data is byte-swapped to the host system's endianess. + * + * If the supplied key_data is not NULL, any key data at the end of the frame will be written into the + * supplied key_data buffer. You can obtain the length to malloc such a buffer with + * libwifi_get_wpa_key_data_length. + */ +int libwifi_get_wpa_data(struct libwifi_frame *frame, struct libwifi_wpa_auth_data *data) { + memset(data, 0, sizeof(struct libwifi_wpa_auth_data)); + + if (libwifi_check_wpa_handshake(frame) < 0) { + return -EINVAL; + } + + struct libwifi_wpa_auth_data *auth_data = + (struct libwifi_wpa_auth_data *) (frame->body + sizeof(struct libwifi_logical_link_ctrl)); + + // Multi-byte fields will be byte-swapped to the host byte order + data->version = auth_data->version; + data->type = auth_data->type; + data->length = ntohs(auth_data->length); + data->descriptor = auth_data->descriptor; + memcpy(&data->key_info, &auth_data->key_info, sizeof(struct libwifi_wpa_key_info)); + data->key_info.information = ntohs(auth_data->key_info.information); + data->key_info.key_length = ntohs(auth_data->key_info.key_length); + data->key_info.replay_counter = be64toh(auth_data->key_info.replay_counter); + data->key_info.key_data_length = ntohs(auth_data->key_info.key_data_length); + + if (data->key_info.key_data_length > 0) { + // Prevent huge allocations in corrupted or malicious frames + if (data->key_info.key_data_length > 1024) { + data->key_info.key_data_length = 1024; + } + + data->key_info.key_data = malloc(data->key_info.key_data_length); + if (data->key_info.key_data == NULL) { + return -ENOMEM; + } + size_t key_data_offset = sizeof(struct libwifi_logical_link_ctrl) + + sizeof(struct libwifi_wpa_auth_data) - sizeof(unsigned char *); + memcpy(data->key_info.key_data, frame->body + key_data_offset, data->key_info.key_data_length); + } + + return 0; +} + +void libwifi_free_wpa_data(struct libwifi_wpa_auth_data *data) { + if (data->key_info.key_data_length > 0) { + free(data->key_info.key_data); + } +} diff --git a/src/libwifi/parse/data/eapol.h b/src/libwifi/parse/data/eapol.h new file mode 100644 index 0000000..08b7a35 --- /dev/null +++ b/src/libwifi/parse/data/eapol.h @@ -0,0 +1,91 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_PARSE_EAPOL_H +#define LIBWIFI_PARSE_EAPOL_H + +#include "../../core/frame/frame.h" +#include "../../core/misc/security.h" + +enum WPA_HANDSHAKE_PART { + HANDSHAKE_M1 = 1, + HANDSHAKE_M2 = 2, + HANDSHAKE_M3 = 4, + HANDSHAKE_M4 = 8, + HANDSHAKE_INVALID = 16 +}; + +/** + * Check if a libwifi_frame contains a WPA1/2 handshake message. + * + * @param libwifi_frame A libwifi_frame + * @return 1 if a handshake is detected, 0 if not. + */ +int libwifi_check_wpa_handshake(struct libwifi_frame *frame); + +/** + * Check what message of the WPA1/2 handshake is in the given frame. + * + * The returned value can be used with the WPA_HANDSHAKE_PART enum, + * such as: + * + * part = libwifi_check_wpa_message(frame); + * if (part & HANDSHAKE_M1) { + * // This is EAPOL Message 1 + * } + * + * @param libwifi_frame A libwifi_frame + * @return A bitmask of parts. + */ +int libwifi_check_wpa_message(struct libwifi_frame *frame); + +/** + * Get a string describing the WPA handshake message inside a supplied libwifi_frame. + * + * @param libwifi_frame A libwifi_frame + * @return A string describing the WPA handshake message found + */ +const char *libwifi_get_wpa_message_string(struct libwifi_frame *frame); + +/** + * Get the length of the key data, if any, present at the end of an EAPOL frame. + * + * @param libwifi_frame A libwifi_frame + * @return The length of the key data + */ +int libwifi_get_wpa_key_data_length(struct libwifi_frame *frame); + +/** + * Get the EAPOL/WPA information from a given libwifi_frame. + * + * As the values in the frame below and including the logical link control layer will be in + * network byte order, the values will be automatically byte swapped if necessary to match + * the host systems byte order. + * + * @param libwifi_frame A libwifi_frame + * @param data A pointer to a libwifi_wpa_auth_data struct + * @return 0 on success, -1 on failure + */ +int libwifi_get_wpa_data(struct libwifi_frame *frame, struct libwifi_wpa_auth_data *data); + +/** + * Free any memory allocated inside of a libwifi_wpa_auth data, such as a buffer + * for WPA key data allocated by the library. + * + * @param data A pointer to a libwifi_wpa_auth_data struct + */ +void libwifi_free_wpa_data(struct libwifi_wpa_auth_data *data); + +#endif /* LIBWIFI_PARSE_EAPOL_H */ diff --git a/src/libwifi/parse/management/assoc_request.c b/src/libwifi/parse/management/assoc_request.c new file mode 100644 index 0000000..5e1f783 --- /dev/null +++ b/src/libwifi/parse/management/assoc_request.c @@ -0,0 +1,79 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "assoc_request.h" +#include "../../core/frame/tag_iterator.h" +#include "common.h" + +#include +#include +#include + +/** + * libwifi_parse_assoc_req will parse useful fields into a struct libwifi_sta. + * + * This function also checks to see if the transmitter address can be ANDed + * with 0x02, to determine a likelihood of randomized addresses. + * + * ┌─────────────────────────────────────────────┐ + * │ Header (Ordered or Unordered) │ ── Association Request Header + * ├─────────────────────────────────────────────┤ + * │ Fixed Parameters │ ─┐ + * ├─────────────────────────────────────────────┤ ├── Association Request Body + * │ Tagged Parameters │ ─┘ + * └─────────────────────────────────────────────┘ + */ +int libwifi_parse_assoc_req(struct libwifi_sta *sta, struct libwifi_frame *frame) { + memset(sta, 0, sizeof(struct libwifi_sta)); + + if (frame->frame_control.type != TYPE_MANAGEMENT || frame->frame_control.subtype != SUBTYPE_ASSOC_REQ) { + return -EINVAL; + } + + if (frame->frame_control.flags.ordered) { + memcpy(sta->transmitter, frame->header.mgmt_ordered.addr2, 6); + memcpy(sta->bssid, frame->header.mgmt_ordered.addr3, 6); + } else { + memcpy(sta->transmitter, frame->header.mgmt_unordered.addr2, 6); + memcpy(sta->bssid, frame->header.mgmt_unordered.addr3, 6); + } + + if (sta->transmitter[0] & 0x02) { + sta->randomized = 1; + } else { + sta->randomized = 0; + } + + // Fixed Parameters must be present + if (frame->len <= (frame->header_len + sizeof(struct libwifi_assoc_req_fixed_parameters))) { + return -EINVAL; + } + + sta->tags.length = (frame->len - frame->header_len); + const unsigned char *tagged_params = frame->body; + sta->tags.parameters = malloc(sta->tags.length); + memcpy(sta->tags.parameters, tagged_params, sta->tags.length); + + struct libwifi_tag_iterator it; + if (libwifi_tag_iterator_init(&it, sta->tags.parameters, sta->tags.length) != 0) { + return -EINVAL; + } + + if (libwifi_sta_tag_parser(sta, &it) != 0) { + return -EINVAL; + } + + return 0; +} diff --git a/src/libwifi/parse/management/assoc_request.h b/src/libwifi/parse/management/assoc_request.h new file mode 100644 index 0000000..2695711 --- /dev/null +++ b/src/libwifi/parse/management/assoc_request.h @@ -0,0 +1,32 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_PARSE_ASSOCREQ_H +#define LIBWIFI_PARSE_ASSOCREQ_H + +#include "../../core/frame/frame.h" +#include "../../core/frame/management/assoc_request.h" +#include "../../core/frame/management/common.h" + +/** + * Parse a association request into a libwifi_sta. + * + * @param sta A libwifi_sta + * @param frame A libwifi_frame + * @return 0 if successful, a negative number if not + */ +int libwifi_parse_assoc_req(struct libwifi_sta *sta, struct libwifi_frame *frame); + +#endif /* LIBWIFI_PARSE_ASSOCREQ_H */ diff --git a/src/libwifi/parse/management/assoc_response.c b/src/libwifi/parse/management/assoc_response.c new file mode 100644 index 0000000..27db560 --- /dev/null +++ b/src/libwifi/parse/management/assoc_response.c @@ -0,0 +1,92 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../../core/frame/management/assoc_response.h" +#include "../../core/frame/frame.h" +#include "../../core/frame/tag.h" +#include "../../core/frame/tag_iterator.h" +#include "../../core/misc/types.h" +#include "../../parse/misc/security.h" +#include "assoc_response.h" +#include "common.h" + +#include +#include +#include + +/** + * libwifi_parse_assoc_resp will parse useful information out of a Probe Response + * into a struct libwifi_bss. As Probe Response frames are very similar to Beacon + * frames, they can be treated in much the same way. + * + * ┌─────────────────────────────────────────────┐ + * │ Header (Ordered or Unordered) │ ── Probe Response Header + * ├─────────────────────────────────────────────┤ + * │ Fixed Parameters │ ─┐ + * ├─────────────────────────────────────────────┤ ├── Probe Response Body + * │ Tagged Parameters │ ─┘ + * └─────────────────────────────────────────────┘ + */ +int libwifi_parse_assoc_resp(struct libwifi_bss *bss, struct libwifi_frame *frame) { + memset(bss, 0, sizeof(struct libwifi_bss)); + + if (frame->frame_control.type != TYPE_MANAGEMENT || frame->frame_control.subtype != SUBTYPE_ASSOC_RESP) { + return -EINVAL; + } + + if (frame->frame_control.flags.ordered) { + memcpy(bss->receiver, frame->header.mgmt_ordered.addr1, 6); + memcpy(bss->transmitter, frame->header.mgmt_ordered.addr2, 6); + memcpy(bss->bssid, frame->header.mgmt_ordered.addr3, 6); + } else { + memcpy(bss->receiver, frame->header.mgmt_unordered.addr1, 6); + memcpy(bss->transmitter, frame->header.mgmt_unordered.addr2, 6); + memcpy(bss->bssid, frame->header.mgmt_unordered.addr3, 6); + } + + // Fixed Parameters must be present + if (frame->len <= (frame->header_len + sizeof(struct libwifi_assoc_resp_fixed_parameters))) { + return -EINVAL; + } + + // At least one Tagged Parameter must be present + if (frame->len < (frame->header_len + sizeof(struct libwifi_assoc_resp_fixed_parameters) + 2)) { + return -EINVAL; + } + + struct libwifi_assoc_resp_fixed_parameters *fixed_params = + (struct libwifi_assoc_resp_fixed_parameters *) frame->body; + if (libwifi_check_capabilities(fixed_params->capabilities_information, CAPABILITIES_PRIVACY)) { + bss->encryption_info |= WEP; + } + + bss->tags.length = + (frame->len - (frame->header_len + sizeof(struct libwifi_assoc_resp_fixed_parameters))); + const unsigned char *tagged_params = frame->body + sizeof(struct libwifi_assoc_resp_fixed_parameters); + bss->tags.parameters = malloc(bss->tags.length); + memcpy(bss->tags.parameters, tagged_params, bss->tags.length); + + // Iterate through common BSS tagged parameters (WPA, RSN, etc) + struct libwifi_tag_iterator it; + memset(&it, 0, sizeof(struct libwifi_tag_iterator)); + if (libwifi_tag_iterator_init(&it, bss->tags.parameters, bss->tags.length) != 0) { + return -EINVAL; + } + if (libwifi_bss_tag_parser(bss, &it) != 0) { + return -EINVAL; + }; + + return 0; +} diff --git a/src/libwifi/parse/management/assoc_response.h b/src/libwifi/parse/management/assoc_response.h new file mode 100644 index 0000000..142388d --- /dev/null +++ b/src/libwifi/parse/management/assoc_response.h @@ -0,0 +1,35 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_PARSE_ASSOCRESP_H +#define LIBWIFI_PARSE_ASSOCRESP_H + +#include +#include + +#include "../../core/frame/frame.h" +#include "../../core/frame/management/common.h" +#include "../../core/misc/security.h" + +/** + * Parse an association response frame into a libwifi_bss. + * + * @param bss A libwifi_bss + * @param frame A libwifi_frame + * @return 0 if successful, a negative number if not. + */ +int libwifi_parse_assoc_resp(struct libwifi_bss *bss, struct libwifi_frame *frame); + +#endif /* LIBWIFI_PARSE_ASSOCRESP_H */ diff --git a/src/libwifi/parse/management/beacon.c b/src/libwifi/parse/management/beacon.c new file mode 100644 index 0000000..bd36daf --- /dev/null +++ b/src/libwifi/parse/management/beacon.c @@ -0,0 +1,91 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../../core/frame/management/beacon.h" +#include "../../core/frame/frame.h" +#include "../../core/frame/tag.h" +#include "../../core/frame/tag_iterator.h" +#include "../../core/misc/types.h" +#include "../../parse/misc/security.h" +#include "beacon.h" +#include "common.h" + +#include +#include +#include +#include + +/** + * libwifi_parse_beacon will parse useful fields out of a supplied beacon frame + * in the format of a struct libwifi_frame. + * + * ┌─────────────────────────────────────────────┐ + * │ Header (Ordered or Unordered) │ ── Beacon Header + * ├─────────────────────────────────────────────┤ + * │ Fixed Parameters │ ─┐ + * ├─────────────────────────────────────────────┤ ├── Beacon Body + * │ Tagged Parameters │ ─┘ + * └─────────────────────────────────────────────┘ + */ +int libwifi_parse_beacon(struct libwifi_bss *bss, struct libwifi_frame *frame) { + memset(bss, 0, sizeof(struct libwifi_bss)); + + if (frame->frame_control.type != TYPE_MANAGEMENT || frame->frame_control.subtype != SUBTYPE_BEACON) { + return -EINVAL; + } + + if (frame->frame_control.flags.ordered) { + memcpy(bss->receiver, frame->header.mgmt_ordered.addr1, 6); + memcpy(bss->transmitter, frame->header.mgmt_ordered.addr2, 6); + memcpy(bss->bssid, frame->header.mgmt_ordered.addr3, 6); + } else { + memcpy(bss->receiver, frame->header.mgmt_unordered.addr1, 6); + memcpy(bss->transmitter, frame->header.mgmt_unordered.addr2, 6); + memcpy(bss->bssid, frame->header.mgmt_unordered.addr3, 6); + } + + // Fixed Parameters must be present + if (frame->len <= (frame->header_len + sizeof(struct libwifi_beacon_fixed_parameters))) { + return -EINVAL; + } + + // At least one Tagged Parameter must be present + if (frame->len < (frame->header_len + sizeof(struct libwifi_beacon_fixed_parameters) + 2)) { + return -EINVAL; + } + + struct libwifi_beacon_fixed_parameters *fixed_params = + (struct libwifi_beacon_fixed_parameters *) frame->body; + if (libwifi_check_capabilities(fixed_params->capabilities_information, CAPABILITIES_PRIVACY)) { + bss->encryption_info |= WEP; + } + + bss->tags.length = (frame->len - (frame->header_len + sizeof(struct libwifi_beacon_fixed_parameters))); + const unsigned char *tagged_params = frame->body + sizeof(struct libwifi_beacon_fixed_parameters); + bss->tags.parameters = malloc(bss->tags.length); + memcpy(bss->tags.parameters, tagged_params, bss->tags.length); + + // Iterate through common BSS tagged parameters (WPA, RSN, etc) + struct libwifi_tag_iterator it; + memset(&it, 0, sizeof(struct libwifi_tag_iterator)); + if (libwifi_tag_iterator_init(&it, bss->tags.parameters, bss->tags.length) != 0) { + return -EINVAL; + } + if (libwifi_bss_tag_parser(bss, &it) != 0) { + return -EINVAL; + }; + + return 0; +} diff --git a/src/libwifi/parse/management/beacon.h b/src/libwifi/parse/management/beacon.h new file mode 100644 index 0000000..8817d32 --- /dev/null +++ b/src/libwifi/parse/management/beacon.h @@ -0,0 +1,35 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_PARSE_BEACON_H +#define LIBWIFI_PARSE_BEACON_H + +#include +#include + +#include "../../core/frame/frame.h" +#include "../../core/frame/management/common.h" +#include "../../core/misc/security.h" + +/** + * Parse useful properties from a beacon frame into a libwifi_bss. + * + * @param bss A libwifi_bss + * @param frame A libwifi_frame + * @return 0 if successful, a negative number if not. + */ +int libwifi_parse_beacon(struct libwifi_bss *bss, struct libwifi_frame *frame); + +#endif /* LIBWIFI_PARSE_BEACON_H */ diff --git a/src/libwifi/parse/management/common.c b/src/libwifi/parse/management/common.c new file mode 100644 index 0000000..14d3d42 --- /dev/null +++ b/src/libwifi/parse/management/common.c @@ -0,0 +1,192 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "common.h" +#include "../../core/frame/tag.h" +#include "../misc/security.h" + +#include +#include +#include +#include + +/** + * Different implementations can have variations of hidden SSIDs. + * It is common to simply set the SSID to an empty string, but some + * devices may "blank" the real SSID without reducing the character count. + * + * Example: "My-SSID" -> "\x00\x00\x00\x00\x00\x00\x00" + */ +void libwifi_handle_ssid_tag(void *target, int target_type, const char *tag_data, int tag_len) { + int hidden = 0; + int null_ssid = 1; + + if (tag_len <= 0) { + hidden = 1; + } else if (tag_len > 32) { + tag_len = 32; + } + + for (int i = 0; i < tag_len; i++) { + if (memcmp(&tag_data[i], "\x00", 1) != 0) { + null_ssid = 0; + break; + } + } + + if (null_ssid) { + hidden = 1; + } + + if (target_type == LIBWIFI_BSS) { + struct libwifi_bss *bss = (struct libwifi_bss *) target; + memcpy(bss->ssid, tag_data, tag_len); + bss->hidden = hidden; + } else if (target_type == LIBWIFI_STA) { + struct libwifi_sta *sta = (struct libwifi_sta *) target; + memcpy(sta->ssid, tag_data, tag_len); + } +} + +/** + * Handle the RSN Tagged Parameter. + * + * At the minimum, the required RSN data is the version and the group cipher suites. + * RSN information is then enumerated within the libwifi_get_rsn_info() function. + */ +int libwifi_bss_handle_rsn_tag(struct libwifi_bss *bss, const unsigned char *rsn_data, int rsn_len) { + struct libwifi_rsn_info rsn_info = {0}; + + bss->encryption_info &= ~(unsigned int) WEP; + + int min_len = sizeof(rsn_info.rsn_version) + sizeof(struct libwifi_cipher_suite); + if (rsn_len < min_len) { + return -EINVAL; + } + + const unsigned char *rsn_end = rsn_data + rsn_len; + + if ((libwifi_get_rsn_info(&rsn_info, rsn_data, rsn_end) != 0)) { + return -EINVAL; + } + + libwifi_enumerate_rsn_suites(&rsn_info, bss); + + memcpy(&bss->rsn_info, &rsn_info, sizeof(struct libwifi_rsn_info)); + + return 0; +} + +/** + * The Microsoft vendor tag is used to advertise WPA and WPS information, as well as + * some other features such as WMM/WME. + * + * The difference between the tags is found via the "Vendor Specific OUI Type" field. + * A common representation of this is XX:XX:XX:YY, such as 00:50:F2:04, where + * 00:50:F2 is the Microsoft OUI and 04 is the type. + * + * It is important to skip the OUI and Type as described above before parsing the data of + * the tag. This is encapsulated with the libwifi_tag_vendor_header struct. + */ +int libwifi_bss_handle_msft_tag(struct libwifi_bss *bss, const unsigned char *msft_data, int msft_len) { + struct libwifi_wpa_info wpa_info = {0}; + struct libwifi_tag_vendor_header *vendor_header = (struct libwifi_tag_vendor_header *) msft_data; + + switch (vendor_header->type) { + case MICROSOFT_OUI_TYPE_WPA: + bss->encryption_info &= ~(unsigned int) WEP; + bss->encryption_info |= WPA; + + // Skip 4 bytes for the OUI (3) and Vendor Tag Type (1) + const unsigned char *wpa_data = msft_data + sizeof(struct libwifi_tag_vendor_header); + const unsigned char *wpa_end = msft_data + (msft_len + sizeof(struct libwifi_tag_vendor_header)); + + if ((libwifi_get_wpa_info(&wpa_info, wpa_data, wpa_end) != 0)) { + return -EINVAL; + } + + libwifi_enumerate_wpa_suites(&wpa_info, bss); + + memcpy(&bss->wpa_info, &wpa_info, sizeof(struct libwifi_wpa_info)); + break; + case MICROSOFT_OUI_TYPE_WMM: + // WMM/WME Supported + break; + case MICROSOFT_OUI_TYPE_WPS: + bss->wps = 1; + break; + } + + return 0; +} + +/** + * This function is a parser for common and useful tags found in frames usually originating + * from the BSS. These include the SSID and DS or HT fields, which can be used to determine + * the channel. + */ +int libwifi_bss_tag_parser(struct libwifi_bss *bss, struct libwifi_tag_iterator *it) { + struct libwifi_tag_vendor_header *vendor_header = NULL; + + do { + switch (it->tag_header->tag_num) { + case TAG_SSID: + libwifi_handle_ssid_tag((void *) bss, LIBWIFI_BSS, (const char *) it->tag_data, + it->tag_header->tag_len); + break; + case TAG_DS_PARAMETER: + case TAG_HT_OPERATION: + memcpy(&bss->channel, it->tag_data, 1); + break; + case TAG_RSN: + if ((libwifi_bss_handle_rsn_tag(bss, it->tag_data, it->tag_header->tag_len) != 0)) { + return -EINVAL; + }; + break; + case TAG_VENDOR_SPECIFIC: + vendor_header = (struct libwifi_tag_vendor_header *) it->tag_data; + + if (memcmp(vendor_header->oui, MICROSOFT_OUI, 3) == 0) { + if ((libwifi_bss_handle_msft_tag(bss, it->tag_data, it->tag_header->tag_len) != 0)) { + return -EINVAL; + } + } + break; + } + } while (libwifi_tag_iterator_next(it) != -1); + + return 0; +} + +/** + * This function is a parser for common and useful tags found in frames usually originating + * from the STA. These include the SSID and DS or HT fields, which can be used to determine + * the channel. + */ +int libwifi_sta_tag_parser(struct libwifi_sta *sta, struct libwifi_tag_iterator *it) { + do { + switch (it->tag_header->tag_num) { + case TAG_SSID: + libwifi_handle_ssid_tag(sta, LIBWIFI_STA, (const char *) it->tag_data, + it->tag_header->tag_len); + break; + case TAG_DS_PARAMETER: + memcpy(&sta->channel, it->tag_data, 1); + break; + } + } while (libwifi_tag_iterator_next(it) != -1); + + return 0; +} diff --git a/src/libwifi/parse/management/common.h b/src/libwifi/parse/management/common.h new file mode 100644 index 0000000..ad6b1dc --- /dev/null +++ b/src/libwifi/parse/management/common.h @@ -0,0 +1,70 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_PARSE_MGMT_COMMON_H +#define LIBWIFI_PARSE_MGMT_COMMON_H + +#include "../../core/frame/management/common.h" +#include "../../core/frame/tag_iterator.h" +#include "../../core/misc/security.h" + +/** + * A helper function to set the SSID of a libwifi_bss, as well as check + * if it is hidden or not. + * + * @param target A libwifi_bss or libwifi_sta + * @param target_type LIBWIFI_BSS or LIBWIFI_STA + * @param ssid The SSID to set + * @param ssid_len The length of the supplied SSID + */ +void libwifi_handle_ssid_tag(void *target, int target_type, const char *ssid, int ssid_len); + +/** + * A helper function to handle the parsing of the RSN IE. + * + * @param bss A libwifi_bss + * @param rsn_data The RSN tag data + * @param rsn_len The length of the RSN tag data + */ +int libwifi_bss_handle_rsn_tag(struct libwifi_bss *bss, const unsigned char *rsn_data, int rsn_len); + +/** + * A helper function to handle the parsing of the Microsoft Vendor IE. + * + * @param bss A libwifi_bss + * @param msft_data The Microsoft vendor tag data + * @param msft_len The length of the Microsoft tag data + */ +int libwifi_bss_handle_msft_tag(struct libwifi_bss *bss, const unsigned char *msft_data, int msft_len); + +/** + * A helper function to iterate through common tags found in a libwifi_bss. + * + * @param bss A libwifi_bss + * @param it A libwifi_tag_iterator + * @return 0 if successful, a negative number if not + */ +int libwifi_bss_tag_parser(struct libwifi_bss *bss, struct libwifi_tag_iterator *it); + +/** + * A helper function to iterate through common tags found in a libwifi_sta. + * + * @param sta A libwifi_sta + * @param it A libwifi_tag_iterator + * @return 0 if successful, a negative number if not + */ +int libwifi_sta_tag_parser(struct libwifi_sta *sta, struct libwifi_tag_iterator *it); + +#endif /* LIBWIFI_PARSE_MGMT_COMMON_H */ diff --git a/src/libwifi/parse/management/deauthentication.c b/src/libwifi/parse/management/deauthentication.c new file mode 100644 index 0000000..1d976dc --- /dev/null +++ b/src/libwifi/parse/management/deauthentication.c @@ -0,0 +1,74 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "deauthentication.h" +#include "common.h" + +#include +#include +#include + +/** + * TODO: potentally write a parsed_to_gen function that converts a parsed deauth back into + * something that can be passed directly into the interface? + */ + +/** + * Deauthentication frames can originate from the BSS or the STA, with no way to know + * who sent the frame by looking at just the frame alone. Because of this, they are + * parsed into a struct libwifi_parsed_deauth instead of a libwifi_bss or libwifi_sta. + * + * ┌─────────────────────────────────────────────┐ + * │ Header (Ordered or Unordered) │ ── Deauthentication Header + * ├─────────────────────────────────────────────┤ + * │ Fixed Parameters │ ─┐ + * ├─────────────────────────────────────────────┤ ├── Deauthentication Body + * │ Tagged Parameters │ ─┘ + * └─────────────────────────────────────────────┘ + */ +int libwifi_parse_deauth(struct libwifi_parsed_deauth *deauth, struct libwifi_frame *frame) { + memset(deauth, 0, sizeof(struct libwifi_parsed_deauth)); + + int tags_len = 0; + + if (frame->frame_control.type != TYPE_MANAGEMENT || frame->frame_control.subtype != SUBTYPE_DEAUTH) { + return -EINVAL; + } + + deauth->ordered = frame->frame_control.flags.ordered; + + if (deauth->ordered) { + memcpy(&deauth->frame_header.ordered, &frame->header.mgmt_ordered, + sizeof(struct libwifi_mgmt_ordered_frame_header)); + tags_len = (frame->len - sizeof(struct libwifi_mgmt_ordered_frame_header) - + sizeof(struct libwifi_deauth_fixed_parameters)); + } else { + memcpy(&deauth->frame_header.unordered, &frame->header.mgmt_unordered, + sizeof(struct libwifi_mgmt_unordered_frame_header)); + tags_len = (frame->len - sizeof(struct libwifi_mgmt_unordered_frame_header) - + sizeof(struct libwifi_deauth_fixed_parameters)); + } + + unsigned char *body = (unsigned char *) frame->body; + + memcpy(&deauth->fixed_parameters, body, sizeof(struct libwifi_deauth_fixed_parameters)); + body += sizeof(struct libwifi_deauth_fixed_parameters); + + deauth->tags.parameters = malloc(tags_len); + memcpy(&deauth->tags.parameters, body, tags_len); + memcpy(&deauth->tags.length, &tags_len, sizeof(tags_len)); + + return 0; +} diff --git a/src/libwifi/parse/management/deauthentication.h b/src/libwifi/parse/management/deauthentication.h new file mode 100644 index 0000000..761e25c --- /dev/null +++ b/src/libwifi/parse/management/deauthentication.h @@ -0,0 +1,25 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_PARSE_DEAUTH_H +#define LIBWIFI_PARSE_DEAUTH_H + +#include "../../core/frame/frame.h" +#include "../../core/frame/management/common.h" +#include "../../core/frame/management/deauthentication.h" + +int libwifi_parse_deauth(struct libwifi_parsed_deauth *deauth, struct libwifi_frame *frame); + +#endif /* LIBWIFI_PARSE_DEAUTH_H */ diff --git a/src/libwifi/parse/management/disassociation.c b/src/libwifi/parse/management/disassociation.c new file mode 100644 index 0000000..2272066 --- /dev/null +++ b/src/libwifi/parse/management/disassociation.c @@ -0,0 +1,72 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "disassociation.h" +#include "common.h" + +#include +#include + +/** + * TODO: potentally write a parsed_to_gen function that converts a parsed disassoc back into + * something that can be passed directly into the interface? + */ + +/** + * Disassociation frames can originate from the BSS or the STA, with no way to know + * who sent the frame by looking at just the frame alone. Because of this, they are + * parsed into a struct libwifi_parsed_deauth instead of a libwifi_bss or libwifi_sta. + * + * ┌─────────────────────────────────────────────┐ + * │ Header (Ordered or Unordered) │ ── Disassociation Header + * ├─────────────────────────────────────────────┤ + * │ Fixed Parameters │ ─┐ + * ├─────────────────────────────────────────────┤ ├── Disassociation Body + * │ Tagged Parameters │ ─┘ + * └─────────────────────────────────────────────┘ + */ +int libwifi_parse_disassoc(struct libwifi_parsed_disassoc *disassoc, struct libwifi_frame *frame) { + memset(disassoc, 0, sizeof(struct libwifi_parsed_disassoc)); + + int tags_len = 0; + + if (frame->frame_control.type != TYPE_MANAGEMENT || frame->frame_control.subtype != SUBTYPE_DISASSOC) { + return -EINVAL; + } + + disassoc->ordered = frame->frame_control.flags.ordered; + + if (disassoc->ordered) { + memcpy(&disassoc->frame_header.ordered, &frame->header.mgmt_ordered, + sizeof(struct libwifi_mgmt_ordered_frame_header)); + tags_len = (frame->len - sizeof(struct libwifi_mgmt_ordered_frame_header) - + sizeof(struct libwifi_disassoc_fixed_parameters)); + } else { + memcpy(&disassoc->frame_header.unordered, &frame->header.mgmt_unordered, + sizeof(struct libwifi_mgmt_unordered_frame_header)); + tags_len = (frame->len - sizeof(struct libwifi_mgmt_unordered_frame_header) - + sizeof(struct libwifi_disassoc_fixed_parameters)); + } + + unsigned char *body = (unsigned char *) frame->body; + + memcpy(&disassoc->fixed_parameters, body, sizeof(struct libwifi_disassoc_fixed_parameters)); + body += sizeof(struct libwifi_disassoc_fixed_parameters); + + memcpy(&disassoc->tags, body, tags_len); + body += tags_len; + + return 0; +} diff --git a/src/libwifi/parse/management/disassociation.h b/src/libwifi/parse/management/disassociation.h new file mode 100644 index 0000000..dc9a086 --- /dev/null +++ b/src/libwifi/parse/management/disassociation.h @@ -0,0 +1,25 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_PARSE_DISASSOC_H +#define LIBWIFI_PARSE_DISASSOC_H + +#include "../../core/frame/frame.h" +#include "../../core/frame/management/common.h" +#include "../../core/frame/management/disassociation.h" + +int libwifi_parse_disassoc(struct libwifi_parsed_disassoc *disassoc, struct libwifi_frame *frame); + +#endif /* LIBWIFI_PARSE_DISASSOC_H */ diff --git a/src/libwifi/parse/management/probe_request.c b/src/libwifi/parse/management/probe_request.c new file mode 100644 index 0000000..7b3fadf --- /dev/null +++ b/src/libwifi/parse/management/probe_request.c @@ -0,0 +1,72 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "probe_request.h" +#include "../../core/frame/tag_iterator.h" +#include "common.h" + +#include +#include +#include + +/** + * libwifi_parse_probe_req will parse useful fields into a struct libwifi_sta. + * + * This function also checks to see if the transmitter address can be ANDed + * with 0x02, to determine a likelihood of randomized addresses. + * + * ┌─────────────────────────────────────────────┐ + * │ Header (Ordered or Unordered) │ ── Probe Request Header + * ├─────────────────────────────────────────────┤ + * │ Tagged Parameters │ ── Probe Request Body + * └─────────────────────────────────────────────┘ + */ +int libwifi_parse_probe_req(struct libwifi_sta *sta, struct libwifi_frame *frame) { + memset(sta, 0, sizeof(struct libwifi_sta)); + + if (frame->frame_control.type != TYPE_MANAGEMENT || frame->frame_control.subtype != SUBTYPE_PROBE_REQ) { + return -EINVAL; + } + + if (frame->frame_control.flags.ordered) { + memcpy(sta->transmitter, frame->header.mgmt_ordered.addr2, 6); + memcpy(sta->bssid, frame->header.mgmt_ordered.addr3, 6); + } else { + memcpy(sta->transmitter, frame->header.mgmt_unordered.addr2, 6); + memcpy(sta->bssid, frame->header.mgmt_unordered.addr3, 6); + } + + if (sta->transmitter[0] & 0x02) { + sta->randomized = 1; + } else { + sta->randomized = 0; + } + + sta->tags.length = (frame->len - frame->header_len); + const unsigned char *tagged_params = frame->body; + sta->tags.parameters = malloc(sta->tags.length); + memcpy(sta->tags.parameters, tagged_params, sta->tags.length); + + struct libwifi_tag_iterator it; + if (libwifi_tag_iterator_init(&it, sta->tags.parameters, sta->tags.length) != 0) { + return -EINVAL; + } + + if (libwifi_sta_tag_parser(sta, &it) != 0) { + return -EINVAL; + } + + return 0; +} diff --git a/src/libwifi/parse/management/probe_request.h b/src/libwifi/parse/management/probe_request.h new file mode 100644 index 0000000..f318b2c --- /dev/null +++ b/src/libwifi/parse/management/probe_request.h @@ -0,0 +1,32 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_PARSE_PROBEREQ_H +#define LIBWIFI_PARSE_PROBEREQ_H + +#include "../../core/frame/frame.h" +#include "../../core/frame/management/common.h" +#include "../../core/frame/management/probe_request.h" + +/** + * Parse a probe request into a libwifi_sta. + * + * @param sta A libwifi_sta + * @param frame A libwifi_frame + * @return 0 if successful, a negative number if not + */ +int libwifi_parse_probe_req(struct libwifi_sta *sta, struct libwifi_frame *frame); + +#endif /* LIBWIFI_PARSE_PROBEREQ_H */ diff --git a/src/libwifi/parse/management/probe_response.c b/src/libwifi/parse/management/probe_response.c new file mode 100644 index 0000000..ed2e27f --- /dev/null +++ b/src/libwifi/parse/management/probe_response.c @@ -0,0 +1,88 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../../core/frame/management/probe_response.h" +#include "../../core/frame/frame.h" +#include "../../core/frame/tag.h" +#include "../../core/frame/tag_iterator.h" +#include "../../core/misc/types.h" +#include "../../parse/misc/security.h" +#include "common.h" +#include "probe_response.h" + +#include +#include +#include + +/** + * libwifi_parse_probe_resp will parse useful information out of a Probe Response + * into a struct libwifi_bss. As Probe Response frames are very similar to Beacon + * frames, they can be treated in much the same way. + * + * ┌─────────────────────────────────────────────┐ + * │ Header (Ordered or Unordered) │ ── Probe Response Header + * ├─────────────────────────────────────────────┤ + * │ Fixed Parameters │ ─┐ + * ├─────────────────────────────────────────────┤ ├── Probe Response Body + * │ Tagged Parameters │ ─┘ + * └─────────────────────────────────────────────┘ + */ +int libwifi_parse_probe_resp(struct libwifi_bss *bss, struct libwifi_frame *frame) { + memset(bss, 0, sizeof(struct libwifi_bss)); + + if (frame->frame_control.type != TYPE_MANAGEMENT || frame->frame_control.subtype != SUBTYPE_PROBE_RESP) { + return -EINVAL; + } + + if (frame->frame_control.flags.ordered) { + memcpy(bss->bssid, frame->header.mgmt_ordered.addr3, 6); + } else { + memcpy(bss->bssid, frame->header.mgmt_unordered.addr3, 6); + } + + // Fixed Parameters must be present + if (frame->len <= (frame->header_len + sizeof(struct libwifi_probe_resp_fixed_parameters))) { + return -EINVAL; + } + + // At least one Tagged Parameter must be present + if (frame->len < (frame->header_len + sizeof(struct libwifi_probe_resp_fixed_parameters) + 2)) { + return -EINVAL; + } + + struct libwifi_probe_resp_fixed_parameters *fixed_params = + (struct libwifi_probe_resp_fixed_parameters *) frame->body; + if (libwifi_check_capabilities(fixed_params->capabilities_information, CAPABILITIES_PRIVACY)) { + bss->encryption_info |= WEP; + } + + bss->tags.length = + (frame->len - (frame->header_len + sizeof(struct libwifi_probe_resp_fixed_parameters))); + const unsigned char *tagged_params = frame->body + sizeof(struct libwifi_probe_resp_fixed_parameters); + bss->tags.parameters = malloc(bss->tags.length); + memcpy(bss->tags.parameters, tagged_params, bss->tags.length); + + // Iterate through common BSS tagged parameters (WPA, RSN, etc) + struct libwifi_tag_iterator it; + memset(&it, 0, sizeof(struct libwifi_tag_iterator)); + if (libwifi_tag_iterator_init(&it, bss->tags.parameters, bss->tags.length) != 0) { + return -EINVAL; + } + if (libwifi_bss_tag_parser(bss, &it) != 0) { + return -EINVAL; + }; + + return 0; +} diff --git a/src/libwifi/parse/management/probe_response.h b/src/libwifi/parse/management/probe_response.h new file mode 100644 index 0000000..6810fed --- /dev/null +++ b/src/libwifi/parse/management/probe_response.h @@ -0,0 +1,35 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_PARSE_PROBERESP_H +#define LIBWIFI_PARSE_PROBERESP_H + +#include +#include + +#include "../../core/frame/frame.h" +#include "../../core/frame/management/common.h" +#include "../../core/misc/security.h" + +/** + * Parse a probe response frame into a libwifi_bss. + * + * @param bss A libwifi_bss + * @param frame A libwifi_frame + * @return 0 if successful, a negative number if not. + */ +int libwifi_parse_probe_resp(struct libwifi_bss *bss, struct libwifi_frame *frame); + +#endif /* LIBWIFI_PARSE_PROBERESP_H */ diff --git a/src/libwifi/parse/management/reassoc_request.c b/src/libwifi/parse/management/reassoc_request.c new file mode 100644 index 0000000..7c4f8ad --- /dev/null +++ b/src/libwifi/parse/management/reassoc_request.c @@ -0,0 +1,79 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "reassoc_request.h" +#include "../../core/frame/tag_iterator.h" +#include "common.h" + +#include +#include +#include + +/** + * libwifi_parse_reassoc_req will parse useful fields into a struct libwifi_sta. + * + * This function also checks to see if the transmitter address can be ANDed + * with 0x02, to determine a likelihood of randomized addresses. + * + * ┌─────────────────────────────────────────────┐ + * │ Header (Ordered or Unordered) │ ── Ressociation Request Header + * ├─────────────────────────────────────────────┤ + * │ Fixed Parameters │ ─┐ + * ├─────────────────────────────────────────────┤ |── Ressociation Request Body + * │ Tagged Parameters │ ─┘ + * └─────────────────────────────────────────────┘ + */ +int libwifi_parse_reassoc_req(struct libwifi_sta *sta, struct libwifi_frame *frame) { + memset(sta, 0, sizeof(struct libwifi_sta)); + + if (frame->frame_control.type != TYPE_MANAGEMENT || frame->frame_control.subtype != SUBTYPE_REASSOC_REQ) { + return -EINVAL; + } + + if (frame->frame_control.flags.ordered) { + memcpy(sta->transmitter, frame->header.mgmt_ordered.addr2, 6); + memcpy(sta->bssid, frame->header.mgmt_ordered.addr3, 6); + } else { + memcpy(sta->transmitter, frame->header.mgmt_unordered.addr2, 6); + memcpy(sta->bssid, frame->header.mgmt_unordered.addr3, 6); + } + + if (sta->transmitter[0] & 0x02) { + sta->randomized = 1; + } else { + sta->randomized = 0; + } + + // Fixed Parameters must be present + if (frame->len <= (frame->header_len + sizeof(struct libwifi_reassoc_req_fixed_parameters))) { + return -EINVAL; + } + + sta->tags.length = (frame->len - frame->header_len); + const unsigned char *tagged_params = frame->body; + sta->tags.parameters = malloc(sta->tags.length); + memcpy(sta->tags.parameters, tagged_params, sta->tags.length); + + struct libwifi_tag_iterator it; + if (libwifi_tag_iterator_init(&it, sta->tags.parameters, sta->tags.length) != 0) { + return -EINVAL; + } + + if (libwifi_sta_tag_parser(sta, &it) != 0) { + return -EINVAL; + } + + return 0; +} diff --git a/src/libwifi/parse/management/reassoc_request.h b/src/libwifi/parse/management/reassoc_request.h new file mode 100644 index 0000000..73e0c79 --- /dev/null +++ b/src/libwifi/parse/management/reassoc_request.h @@ -0,0 +1,32 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_PARSE_REASSOCREQ_H +#define LIBWIFI_PARSE_REASSOCREQ_H + +#include "../../core/frame/frame.h" +#include "../../core/frame/management/common.h" +#include "../../core/frame/management/reassoc_request.h" + +/** + * Parse a reassociation request into a libwifi_sta. + * + * @param sta A libwifi_sta + * @param frame A libwifi_frame + * @return 0 if successful, a negative number if not + */ +int libwifi_parse_reassoc_req(struct libwifi_sta *sta, struct libwifi_frame *frame); + +#endif /* LIBWIFI_PARSE_REASSOCREQ_H */ diff --git a/src/libwifi/parse/management/reassoc_response.c b/src/libwifi/parse/management/reassoc_response.c new file mode 100644 index 0000000..2c92827 --- /dev/null +++ b/src/libwifi/parse/management/reassoc_response.c @@ -0,0 +1,92 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../../core/frame/management/reassoc_response.h" +#include "../../core/frame/frame.h" +#include "../../core/frame/tag.h" +#include "../../core/frame/tag_iterator.h" +#include "../../core/misc/types.h" +#include "../../parse/misc/security.h" +#include "common.h" +#include "reassoc_response.h" + +#include +#include +#include + +/** + * libwifi_parse_reassoc_resp will parse useful information out of a Reassocation Response + * into a struct libwifi_bss. + * + * ┌─────────────────────────────────────────────┐ + * │ Header (Ordered or Unordered) │ ── Reassocation Response Header + * ├─────────────────────────────────────────────┤ + * │ Fixed Parameters │ ─┐ + * ├─────────────────────────────────────────────┤ ├── Reassociation Response Body + * │ Tagged Parameters │ ─┘ + * └─────────────────────────────────────────────┘ + */ +int libwifi_parse_reassoc_resp(struct libwifi_bss *bss, struct libwifi_frame *frame) { + memset(bss, 0, sizeof(struct libwifi_bss)); + + if (frame->frame_control.type != TYPE_MANAGEMENT || + frame->frame_control.subtype != SUBTYPE_REASSOC_RESP) { + return -EINVAL; + } + + if (frame->frame_control.flags.ordered) { + memcpy(bss->receiver, frame->header.mgmt_ordered.addr1, 6); + memcpy(bss->transmitter, frame->header.mgmt_ordered.addr2, 6); + memcpy(bss->bssid, frame->header.mgmt_ordered.addr3, 6); + } else { + memcpy(bss->receiver, frame->header.mgmt_unordered.addr1, 6); + memcpy(bss->transmitter, frame->header.mgmt_unordered.addr2, 6); + memcpy(bss->bssid, frame->header.mgmt_unordered.addr3, 6); + } + + // Fixed Parameters must be present + if (frame->len <= (frame->header_len + sizeof(struct libwifi_reassoc_resp_fixed_parameters))) { + return -EINVAL; + } + + // At least one Tagged Parameter must be present + if (frame->len < (frame->header_len + sizeof(struct libwifi_reassoc_resp_fixed_parameters) + 2)) { + return -EINVAL; + } + + struct libwifi_reassoc_resp_fixed_parameters *fixed_params = + (struct libwifi_reassoc_resp_fixed_parameters *) frame->body; + if (libwifi_check_capabilities(fixed_params->capabilities_information, CAPABILITIES_PRIVACY)) { + bss->encryption_info |= WEP; + } + + bss->tags.length = + (frame->len - (frame->header_len + sizeof(struct libwifi_reassoc_resp_fixed_parameters))); + const unsigned char *tagged_params = frame->body + sizeof(struct libwifi_reassoc_resp_fixed_parameters); + bss->tags.parameters = malloc(bss->tags.length); + memcpy(bss->tags.parameters, tagged_params, bss->tags.length); + + // Iterate through common BSS tagged parameters (WPA, RSN, etc) + struct libwifi_tag_iterator it; + memset(&it, 0, sizeof(struct libwifi_tag_iterator)); + if (libwifi_tag_iterator_init(&it, bss->tags.parameters, bss->tags.length) != 0) { + return -EINVAL; + } + if (libwifi_bss_tag_parser(bss, &it) != 0) { + return -EINVAL; + }; + + return 0; +} diff --git a/src/libwifi/parse/management/reassoc_response.h b/src/libwifi/parse/management/reassoc_response.h new file mode 100644 index 0000000..ba14a6d --- /dev/null +++ b/src/libwifi/parse/management/reassoc_response.h @@ -0,0 +1,35 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_PARSE_REASSOCRESP_H +#define LIBWIFI_PARSE_REASSOCRESP_H + +#include +#include + +#include "../../core/frame/frame.h" +#include "../../core/frame/management/common.h" +#include "../../core/misc/security.h" + +/** + * Parse a reassociation response frame into a libwifi_bss. + * + * @param bss A libwifi_bss + * @param frame A libwifi_frame + * @return 0 if successful, a negative number if not. + */ +int libwifi_parse_reassoc_resp(struct libwifi_bss *bss, struct libwifi_frame *frame); + +#endif /* LIBWIFI_PARSE_REASSOCRESP_H */ diff --git a/src/libwifi/parse/misc/radiotap.c b/src/libwifi/parse/misc/radiotap.c new file mode 100644 index 0000000..176167e --- /dev/null +++ b/src/libwifi/parse/misc/radiotap.c @@ -0,0 +1,126 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "radiotap.h" +#include "../../core/radiotap/radiotap_iter.h" + +#include +#include + +/** + * The libwifi radiotap parser uses the usual ieee80211_radiotap_iterator to parse incoming + * radiotap headers into a consumable libwifi_radiotap_info struct. + */ +void libwifi_parse_radiotap_info(struct libwifi_radiotap_info *info, const unsigned char *frame) { + memset(info, 0, sizeof(struct libwifi_radiotap_info)); + + struct ieee80211_radiotap_header *rh = (struct ieee80211_radiotap_header *) frame; + struct ieee80211_radiotap_iterator it = {0}; + int ret = ieee80211_radiotap_iterator_init(&it, (void *) frame, rh->it_len, NULL); + + int skipped_antenna = 0; + info->length = rh->it_len; + + while (!ret) { + switch (it.this_arg_index) { + case IEEE80211_RADIOTAP_CHANNEL: + info->channel.freq = le16toh(*(uint16_t *) it.this_arg); + info->channel.flags = le16toh(*(uint16_t *) (it.this_arg + 2)); + break; + case IEEE80211_RADIOTAP_RATE: + info->rate_raw = *it.this_arg; + info->rate = (*it.this_arg / 2.0); + break; + case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: + // Radiotap Headers will include the ANTSIGNAL without an explicit Antenna definition. + if (!skipped_antenna) { + info->signal = *it.this_arg; + skipped_antenna = 1; + break; + } + + if (info->antenna_count < LIBWIFI_MAX_RADIOTAP_ANTENNAS) { + struct libwifi_radiotap_antenna antenna = {.antenna_number = info->antenna_count, + .signal = *it.this_arg}; + info->antennas[info->antenna_count] = antenna; + info->antenna_count += 1; + } + break; + case IEEE80211_RADIOTAP_ANTENNA: + info->antennas[info->antenna_count - 1].antenna_number = *it.this_arg; + break; + case IEEE80211_RADIOTAP_DBM_ANTNOISE: + break; + case IEEE80211_RADIOTAP_FLAGS: + info->flags = *it.this_arg; + break; + case IEEE80211_RADIOTAP_EXT: + info->extended_flags = *it.this_arg; + break; + case IEEE80211_RADIOTAP_RX_FLAGS: + info->rx_flags = *it.this_arg; + break; + case IEEE80211_RADIOTAP_TX_FLAGS: + info->tx_flags = *it.this_arg; + break; + case IEEE80211_RADIOTAP_MCS: + info->mcs.known = *(uint8_t *) it.this_arg; + info->mcs.flags = *(uint8_t *) (it.this_arg + 2); + info->mcs.mcs = *(uint8_t *) (it.this_arg + 3); + break; + case IEEE80211_RADIOTAP_DBM_TX_POWER: + info->tx_power = *it.this_arg; + break; + case IEEE80211_RADIOTAP_TIMESTAMP: + info->timestamp.timestamp = le64toh(*(uint64_t *) it.this_arg); + info->timestamp.accuracy = le16toh(*(uint16_t *) (it.this_arg + 2)); + info->timestamp.unit = *(uint8_t *) (it.this_arg + 3); + info->timestamp.flags = *(uint8_t *) (it.this_arg + 4); + break; + case IEEE80211_RADIOTAP_RTS_RETRIES: + info->rts_retries = *it.this_arg; + break; + case IEEE80211_RADIOTAP_DATA_RETRIES: + info->data_retries = *it.this_arg; + break; + } + + ret = ieee80211_radiotap_iterator_next(&it); + } +} + +/** + * A simpler function than the main libwifi_parse_radiotap_info function, designed to extract + * only the signal strength field. + */ +int8_t libwifi_parse_radiotap_rssi(const unsigned char *frame) { + struct ieee80211_radiotap_header *rh = (struct ieee80211_radiotap_header *) frame; + + int8_t rssi = 0; + + struct ieee80211_radiotap_iterator it; + int ret = ieee80211_radiotap_iterator_init(&it, (void *) frame, rh->it_len, NULL); + + while (!ret) { + if (it.this_arg_index == IEEE80211_RADIOTAP_DBM_ANTSIGNAL) { + rssi = *it.this_arg; + break; + } + + ret = ieee80211_radiotap_iterator_next(&it); + } + + return rssi; +} diff --git a/src/libwifi/parse/misc/radiotap.h b/src/libwifi/parse/misc/radiotap.h new file mode 100644 index 0000000..8f74e6a --- /dev/null +++ b/src/libwifi/parse/misc/radiotap.h @@ -0,0 +1,39 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_PARSE_RADIOTAP_H +#define LIBWIFI_PARSE_RADIOTAP_H + +#include "../../core/misc/radiotap.h" +#include + +/** + * Parse the radiotap information out of a raw frame into a + * libwifi_radiotap_info. + * + * @param info A libwifi_radiotap_info + * @param frame A raw 802.11 frame + */ +void libwifi_parse_radiotap_info(struct libwifi_radiotap_info *info, const unsigned char *frame); + +/** + * Retrieve the signal strength from a raw frame via radiotap header. + * + * @param frame A raw 802.11 frame + * @return signal strength in dBm + */ +int8_t libwifi_parse_radiotap_rssi(const unsigned char *frame); + +#endif /* LIBWIFI_PARSE_RADIOTAP_H */ diff --git a/src/libwifi/parse/misc/security.c b/src/libwifi/parse/misc/security.c new file mode 100644 index 0000000..bf211f7 --- /dev/null +++ b/src/libwifi/parse/misc/security.c @@ -0,0 +1,685 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "security.h" +#include "../../core/misc/byteswap.h" + +#include +#include +#include +#include + +/** + * RSN Information is supplied via the raw tag data. The supplied data is then "walked" + * through as a pointer to extract the details of the tag and write them into + * a struct libwifi_rsn_info. + * + * libwifi supports a maximum of 3 Pairwise Cipher Suites and 3 Auth Key Management Suites. + * The Version, Group Cipher Suite and Capabilities fields are all required. + */ +int libwifi_get_rsn_info(struct libwifi_rsn_info *info, const unsigned char *tag_data, + const unsigned char *tag_end) { + memset(info, 0, sizeof(struct libwifi_rsn_info)); + + // Create a pointer we can manipulate from the tag data + unsigned char *data = (unsigned char *) tag_data; + + // Handle the RSN Version + memcpy(&info->rsn_version, data, sizeof(info->rsn_version)); + data += sizeof(info->rsn_version); + + // Handle the RSN Group Cipher Suites + memcpy(&info->group_cipher_suite, data, sizeof(struct libwifi_cipher_suite)); + data += sizeof(struct libwifi_cipher_suite); + + // Bounds check and handle the RSN Pairwise Ciphers + if (data > tag_end) { + return -EINVAL; + } + if ((data + sizeof(uint16_t)) > tag_end) { + return -EINVAL; + } + uint16_t suite_count = *data; + if (suite_count > LIBWIFI_MAX_CIPHER_SUITES) { + suite_count = LIBWIFI_MAX_CIPHER_SUITES; + } + data += sizeof(suite_count); + if ((((suite_count * sizeof(struct libwifi_cipher_suite)) + data)) > tag_end) { + return -EINVAL; + } + info->num_pairwise_cipher_suites = suite_count; + + // Iterate through the found Pairwise Ciphers, adding them each time + struct wifi_cipher_suite *cur_cipher_suite = NULL; + for (int i = 0; i < suite_count; ++i) { + if (data > tag_end) { + return -EINVAL; + } + cur_cipher_suite = (struct wifi_cipher_suite *) data; + memcpy(&info->pairwise_cipher_suites[i], cur_cipher_suite, sizeof(struct libwifi_cipher_suite)); + info->pairwise_cipher_suites[i].suite_type = info->pairwise_cipher_suites[i].suite_type; + data += sizeof(struct libwifi_cipher_suite); + } + + // Bounds check and handle the RSN Authentication Key Management Suites + if ((data + sizeof(suite_count)) > tag_end) { + return -EINVAL; + } + suite_count = *data; + if (suite_count > LIBWIFI_MAX_CIPHER_SUITES) { + suite_count = LIBWIFI_MAX_CIPHER_SUITES; + } + data += sizeof(suite_count); + if ((((suite_count * sizeof(struct libwifi_cipher_suite)) + data)) > tag_end) { + return -EINVAL; + } + info->num_auth_key_mgmt_suites = suite_count; + + // Iterate through the found Auth Key Management Suites, adding them each time + for (int i = 0; i < suite_count; ++i) { + if (data > tag_end) { + return -EINVAL; + } + cur_cipher_suite = (struct wifi_cipher_suite *) data; + memcpy(&info->auth_key_mgmt_suites[i], cur_cipher_suite, sizeof(struct libwifi_cipher_suite)); + info->auth_key_mgmt_suites[i].suite_type = info->auth_key_mgmt_suites[i].suite_type; + data += sizeof(struct libwifi_cipher_suite); + } + + // Bounds check and handle the RSN Capabilities field + if (data > tag_end) { + return -EINVAL; + } + memcpy(&info->rsn_capabilities, data, sizeof(info->rsn_capabilities)); + + return 0; +} + +/** + * This function will enumerate over a supplied struct libwifi_rsn_info and write + * the following into a supplied struct libwifi_bss: + * + * - Group Cipher Suite + * - Up to 3 Pairwise Cipher Suites + * - Up to 3 Auth Key Management Suites + * - The WPA Type (WPA2 or WPA3) + * + * The bss->encryption_info field is a 64-bit wide bitmask. The larger length is + * required to accomodate the different types of cipher suites without having + * any overlap between group cipher and pairwise cipher. + */ +void libwifi_enumerate_rsn_suites(struct libwifi_rsn_info *rsn_info, struct libwifi_bss *bss) { + switch (rsn_info->group_cipher_suite.suite_type) { + case CIPHER_SUITE_WEP40: + bss->encryption_info |= LIBWIFI_GROUP_CIPHER_SUITE_WEP40; + break; + case CIPHER_SUITE_TKIP: + bss->encryption_info |= LIBWIFI_GROUP_CIPHER_SUITE_TKIP; + break; + case CIPHER_SUITE_RESERVED: + bss->encryption_info |= LIBWIFI_GROUP_CIPHER_SUITE_RESERVED; + break; + case CIPHER_SUITE_CCMP128: + bss->encryption_info |= LIBWIFI_GROUP_CIPHER_SUITE_CCMP128; + break; + case CIPHER_SUITE_WEP104: + bss->encryption_info |= LIBWIFI_GROUP_CIPHER_SUITE_WEP104; + break; + case CIPHER_SUITE_BIP_CMAC128: + bss->encryption_info |= LIBWIFI_GROUP_CIPHER_SUITE_BIP_CMAC128; + break; + case CIPHER_SUITE_NOTALLOWED: + bss->encryption_info |= LIBWIFI_GROUP_CIPHER_SUITE_NOTALLOWED; + break; + case CIPHER_SUITE_GCMP128: + bss->encryption_info |= LIBWIFI_GROUP_CIPHER_SUITE_GCMP128; + break; + case CIPHER_SUITE_GCMP256: + bss->encryption_info |= LIBWIFI_GROUP_CIPHER_SUITE_GCMP256; + break; + case CIPHER_SUITE_CCMP256: + bss->encryption_info |= LIBWIFI_GROUP_CIPHER_SUITE_CCMP256; + break; + case CIPHER_SUITE_BIP_GMAC128: + bss->encryption_info |= LIBWIFI_GROUP_CIPHER_SUITE_BIP_GMAC128; + break; + case CIPHER_SUITE_BIP_GMAC256: + bss->encryption_info |= LIBWIFI_GROUP_CIPHER_SUITE_BIP_GMAC256; + break; + case CIPHER_SUITE_BIP_CMAC256: + bss->encryption_info |= LIBWIFI_GROUP_CIPHER_SUITE_BIP_CMAC256; + break; + default: + break; + } + + for (int i = 0; i < rsn_info->num_pairwise_cipher_suites; ++i) { + if ((memcmp(rsn_info->pairwise_cipher_suites[i].oui, CIPHER_SUITE_OUI, 3) == 0)) { + switch (rsn_info->pairwise_cipher_suites[i].suite_type) { + case CIPHER_SUITE_GROUP: + bss->encryption_info |= LIBWIFI_PAIRWISE_SUITE_GROUP; + break; + case CIPHER_SUITE_TKIP: + bss->encryption_info |= LIBWIFI_PAIRWISE_CIPHER_SUITE_TKIP; + break; + case CIPHER_SUITE_RESERVED: + bss->encryption_info |= LIBWIFI_PAIRWISE_CIPHER_SUITE_RESERVED; + break; + case CIPHER_SUITE_CCMP128: + bss->encryption_info |= LIBWIFI_PAIRWISE_CIPHER_SUITE_CCMP128; + break; + case CIPHER_SUITE_BIP_CMAC128: + bss->encryption_info |= LIBWIFI_PAIRWISE_CIPHER_SUITE_BIP_CMAC128; + break; + case CIPHER_SUITE_NOTALLOWED: + bss->encryption_info |= LIBWIFI_PAIRWISE_CIPHER_SUITE_NOTALLOWED; + break; + case CIPHER_SUITE_GCMP128: + bss->encryption_info |= LIBWIFI_PAIRWISE_CIPHER_SUITE_GCMP128; + break; + case CIPHER_SUITE_GCMP256: + bss->encryption_info |= LIBWIFI_PAIRWISE_CIPHER_SUITE_GCMP256; + break; + case CIPHER_SUITE_CCMP256: + bss->encryption_info |= LIBWIFI_PAIRWISE_CIPHER_SUITE_CCMP256; + break; + case CIPHER_SUITE_BIP_GMAC128: + bss->encryption_info |= LIBWIFI_PAIRWISE_CIPHER_SUITE_BIP_GMAC128; + break; + case CIPHER_SUITE_BIP_GMAC256: + bss->encryption_info |= LIBWIFI_PAIRWISE_CIPHER_SUITE_BIP_GMAC256; + break; + case CIPHER_SUITE_BIP_CMAC256: + bss->encryption_info |= LIBWIFI_PAIRWISE_CIPHER_SUITE_BIP_CMAC256; + break; + default: + break; + } + } + } + + for (int i = 0; i < rsn_info->num_auth_key_mgmt_suites; ++i) { + if (memcmp(rsn_info->auth_key_mgmt_suites[i].oui, CIPHER_SUITE_OUI, 3) == 0) { + switch (rsn_info->auth_key_mgmt_suites[i].suite_type) { + case AKM_SUITE_RESERVED: + bss->encryption_info |= WPA2; + bss->encryption_info |= LIBWIFI_AKM_SUITE_RESERVED; + break; + case AKM_SUITE_1X: + bss->encryption_info |= WPA2; + bss->encryption_info |= LIBWIFI_AKM_SUITE_1X; + break; + case AKM_SUITE_PSK: + bss->encryption_info |= WPA2; + bss->encryption_info |= LIBWIFI_AKM_SUITE_PSK; + break; + case AKM_SUITE_1X_FT: + bss->encryption_info |= WPA2; + bss->encryption_info |= LIBWIFI_AKM_SUITE_1X_FT; + break; + case AKM_SUITE_PSK_FT: + bss->encryption_info |= WPA2; + bss->encryption_info |= LIBWIFI_AKM_SUITE_PSK_FT; + break; + case AKM_SUITE_1X_SHA256: + bss->encryption_info |= WPA2; + bss->encryption_info |= LIBWIFI_AKM_SUITE_1X_SHA256; + break; + case AKM_SUITE_PSK_SHA256: + bss->encryption_info |= WPA2; + bss->encryption_info |= LIBWIFI_AKM_SUITE_PSK_SHA256; + break; + case AKM_SUITE_TDLS: + bss->encryption_info |= WPA2; + bss->encryption_info |= LIBWIFI_AKM_SUITE_TDLS; + break; + case AKM_SUITE_SAE: + bss->encryption_info |= WPA3; + bss->encryption_info |= LIBWIFI_AKM_SUITE_SAE; + break; + case AKM_SUITE_SAE_FT: + bss->encryption_info |= WPA3; + bss->encryption_info |= LIBWIFI_AKM_SUITE_SAE_FT; + break; + case AKM_SUITE_AP_PEER: + bss->encryption_info |= WPA3; + bss->encryption_info |= LIBWIFI_AKM_SUITE_AP_PEER; + break; + case AKM_SUITE_1X_SUITEB_SHA256: + bss->encryption_info |= WPA3; + bss->encryption_info |= LIBWIFI_AKM_SUITE_1X_SUITEB_SHA256; + break; + case AKM_SUITE_1X_SUITEB_SHA384: + bss->encryption_info |= WPA3; + bss->encryption_info |= LIBWIFI_AKM_SUITE_1X_SUITEB_SHA384; + break; + case AKM_SUITE_1X_FT_SHA384: + bss->encryption_info |= WPA3; + bss->encryption_info |= LIBWIFI_AKM_SUITE_1X_FT_SHA384; + break; + case AKM_SUITE_FILS_SHA256: + bss->encryption_info |= WPA2; + bss->encryption_info |= LIBWIFI_AKM_SUITE_FILS_SHA256; + break; + case AKM_SUITE_FILS_SHA384: + bss->encryption_info |= WPA3; + bss->encryption_info |= LIBWIFI_AKM_SUITE_FILS_SHA384; + break; + case AKM_SUITE_FILS_SHA256_FT: + bss->encryption_info |= WPA2; + bss->encryption_info |= LIBWIFI_AKM_SUITE_FILS_SHA256_FT; + break; + case AKM_SUITE_FILS_SHA384_FT: + bss->encryption_info |= WPA3; + bss->encryption_info |= LIBWIFI_AKM_SUITE_FILS_SHA384_FT; + break; + case AKM_SUITE_OWE: + bss->encryption_info |= WPA3; + bss->encryption_info |= LIBWIFI_AKM_SUITE_OWE; + break; + case AKM_PSK_SHA384_FT: + bss->encryption_info |= WPA3; + bss->encryption_info |= LIBWIFI_AKM_PSK_SHA384_FT; + break; + case AKM_PSK_SHA384: + bss->encryption_info |= WPA3; + bss->encryption_info |= LIBWIFI_AKM_PSK_SHA384; + break; + default: + break; + } + } + } +} + +/** + * Similar to libwifi_get_rsn_info, WPA Information is supplied via the raw tag data. + * The supplied data is then "walked" through as a pointer to extract the details of + * the tag and write them into a struct libwifi_wpa_info. + * + * libwifi supports a maximum of 3 Unicast Cipher Suites and 3 Auth Key Management Suites. + * The Version and Multicast Cipher Suite fields are required. + */ +int libwifi_get_wpa_info(struct libwifi_wpa_info *info, const unsigned char *tag_data, + const unsigned char *tag_end) { + memset(info, 0, sizeof(struct libwifi_wpa_info)); + + // Create a pointer we can manipulate from the tag data + unsigned char *data = ((unsigned char *) tag_data); + + // Handle the WPA Version + memcpy(&info->wpa_version, data, sizeof(info->wpa_version)); + data += sizeof(info->wpa_version); + + // Handle the WPA Multicast Cipher Suite + memcpy(&info->multicast_cipher_suite, data, sizeof(struct libwifi_cipher_suite)); + data += sizeof(struct libwifi_cipher_suite); + + // Bounds check and handle the WPA Unicast Cipher Suites + if (data > tag_end) { + return -EINVAL; + } + if ((data + sizeof(uint16_t)) > tag_end) { + return -EINVAL; + } + uint16_t suite_count = *data; + if (suite_count > LIBWIFI_MAX_CIPHER_SUITES) { + suite_count = LIBWIFI_MAX_CIPHER_SUITES; + } + data += sizeof(suite_count); + if ((((suite_count * sizeof(struct libwifi_cipher_suite)) + data)) > tag_end) { + return -EINVAL; + } + info->num_unicast_cipher_suites = suite_count; + + // Iterate through the found Unicast Ciphers, adding them each time + struct wifi_cipher_suite *cur_cipher_suite = NULL; + for (int i = 0; i < suite_count; ++i) { + if (data > tag_end) { + return -EINVAL; + } + cur_cipher_suite = (struct wifi_cipher_suite *) data; + memcpy(&info->unicast_cipher_suites[i], cur_cipher_suite, sizeof(struct libwifi_cipher_suite)); + info->unicast_cipher_suites[i].suite_type = info->unicast_cipher_suites[i].suite_type; + data += sizeof(struct libwifi_cipher_suite); + } + + // Bounds check and handle the WPA Authentication Key Management Suites + if ((data + sizeof(suite_count)) > tag_end) { + return -EINVAL; + } + suite_count = *data; + if (suite_count > LIBWIFI_MAX_CIPHER_SUITES) { + suite_count = LIBWIFI_MAX_CIPHER_SUITES; + } + data += sizeof(suite_count); + if ((((suite_count * sizeof(struct libwifi_cipher_suite)) + data)) > tag_end) { + return -EINVAL; + } + info->num_auth_key_mgmt_suites = suite_count; + + // Iterate through the found Auth Key Management Suites, adding them each time + for (int i = 0; i < suite_count; ++i) { + if (data > tag_end) { + return -EINVAL; + } + cur_cipher_suite = (struct wifi_cipher_suite *) data; + memcpy(&info->auth_key_mgmt_suites[i], cur_cipher_suite, sizeof(struct libwifi_cipher_suite)); + info->auth_key_mgmt_suites[i].suite_type = info->auth_key_mgmt_suites[i].suite_type; + data += sizeof(struct libwifi_cipher_suite); + } + + return 0; +} + +/** + * Similarly to libwifi_enumerate_wpa_suites, this function will enumerate over a supplied + * struct libwifi_wpa_info and write the following into a supplied struct libwifi_bss: + * + * - Multicast Cipher Suite + * - Up to 3 Unicast Cipher Suites + * - Up to 3 Auth Key Management Suites + * + * The bss->encryption_info field is a 64-bit wide bitmask. The larger length is + * required to accomodate the different types of cipher suites without having + * any overlap between group cipher and pairwise cipher. + */ +void libwifi_enumerate_wpa_suites(struct libwifi_wpa_info *wpa_info, struct libwifi_bss *bss) { + switch (wpa_info->multicast_cipher_suite.suite_type) { + case CIPHER_SUITE_WEP40: + bss->encryption_info |= LIBWIFI_GROUP_CIPHER_SUITE_WEP40; + break; + case CIPHER_SUITE_WEP104: + bss->encryption_info |= LIBWIFI_GROUP_CIPHER_SUITE_WEP104; + break; + case CIPHER_SUITE_TKIP: + bss->encryption_info |= LIBWIFI_GROUP_CIPHER_SUITE_TKIP; + break; + case CIPHER_SUITE_RESERVED: + bss->encryption_info |= LIBWIFI_GROUP_CIPHER_SUITE_RESERVED; + break; + default: + break; + } + + for (int i = 0; i < wpa_info->num_unicast_cipher_suites; ++i) { + if ((memcmp(wpa_info->unicast_cipher_suites[i].oui, MICROSOFT_OUI, 3) == 0)) { + switch (wpa_info->unicast_cipher_suites[i].suite_type) { + case CIPHER_SUITE_GROUP: + bss->encryption_info |= LIBWIFI_PAIRWISE_SUITE_GROUP; + break; + case CIPHER_SUITE_TKIP: + bss->encryption_info |= LIBWIFI_PAIRWISE_CIPHER_SUITE_TKIP; + break; + case CIPHER_SUITE_RESERVED: + bss->encryption_info |= LIBWIFI_PAIRWISE_CIPHER_SUITE_RESERVED; + break; + case CIPHER_SUITE_WEP40: + bss->encryption_info |= LIBWIFI_PAIRWISE_CIPHER_SUITE_WEP40; + break; + case CIPHER_SUITE_WEP104: + bss->encryption_info |= LIBWIFI_PAIRWISE_CIPHER_SUITE_WEP104; + break; + default: + break; + } + } + } + + for (int i = 0; i < wpa_info->num_auth_key_mgmt_suites; ++i) { + if (memcmp(wpa_info->auth_key_mgmt_suites[i].oui, MICROSOFT_OUI, 3) == 0) { + switch (wpa_info->auth_key_mgmt_suites[i].suite_type) { + case AKM_SUITE_RESERVED: + bss->encryption_info |= WPA; + bss->encryption_info |= LIBWIFI_AKM_SUITE_RESERVED; + break; + case AKM_SUITE_1X: + bss->encryption_info |= WPA; + bss->encryption_info |= LIBWIFI_AKM_SUITE_1X; + break; + case AKM_SUITE_PSK: + bss->encryption_info |= WPA; + bss->encryption_info |= LIBWIFI_AKM_SUITE_PSK; + break; + case AKM_SUITE_1X_FT: + bss->encryption_info |= WPA; + bss->encryption_info |= LIBWIFI_AKM_SUITE_1X_FT; + break; + case AKM_SUITE_PSK_FT: + bss->encryption_info |= WPA; + bss->encryption_info |= LIBWIFI_AKM_SUITE_PSK_FT; + break; + } + } + } +} + +void libwifi_get_security_type(struct libwifi_bss *bss, char *buf) { + memset(buf, 0, LIBWIFI_SECURITY_BUF_LEN); + + int offset = 0; + int append = 0; + + if (bss->encryption_info == 0) { + snprintf(buf, LIBWIFI_SECURITY_BUF_LEN, "None"); + return; + } + + if (bss->encryption_info & WPA3) { + _libwifi_add_sec_item(buf, &offset, &append, "WPA3"); + } + if (bss->encryption_info & WPA2) { + _libwifi_add_sec_item(buf, &offset, &append, "WPA2"); + } + if (bss->encryption_info & WPA) { + _libwifi_add_sec_item(buf, &offset, &append, "WPA"); + } + if (bss->encryption_info & WEP) { + _libwifi_add_sec_item(buf, &offset, &append, "WEP"); + } +} + +void libwifi_get_group_ciphers(struct libwifi_bss *bss, char *buf) { + memset(buf, 0, LIBWIFI_SECURITY_BUF_LEN); + + int offset = 0; + int append = 0; + + if (bss->encryption_info == 0) { + snprintf(buf + offset, LIBWIFI_SECURITY_BUF_LEN, "None"); + return; + } + + if (bss->encryption_info & LIBWIFI_GROUP_CIPHER_SUITE_WEP40) { + _libwifi_add_sec_item(buf, &offset, &append, "WEP40"); + } + if (bss->encryption_info & LIBWIFI_GROUP_CIPHER_SUITE_TKIP) { + _libwifi_add_sec_item(buf, &offset, &append, "TKIP"); + } + if (bss->encryption_info & LIBWIFI_GROUP_CIPHER_SUITE_RESERVED) { + _libwifi_add_sec_item(buf, &offset, &append, "RESERVED"); + } + if (bss->encryption_info & LIBWIFI_GROUP_CIPHER_SUITE_CCMP128) { + _libwifi_add_sec_item(buf, &offset, &append, "CCMP128"); + } + if (bss->encryption_info & LIBWIFI_GROUP_CIPHER_SUITE_WEP104) { + _libwifi_add_sec_item(buf, &offset, &append, "WEP104"); + } + if (bss->encryption_info & LIBWIFI_GROUP_CIPHER_SUITE_BIP_CMAC128) { + _libwifi_add_sec_item(buf, &offset, &append, "BIP_CMAC128"); + } + if (bss->encryption_info & LIBWIFI_GROUP_CIPHER_SUITE_NOTALLOWED) { + _libwifi_add_sec_item(buf, &offset, &append, "NOT_ALLOWED"); + } + if (bss->encryption_info & LIBWIFI_GROUP_CIPHER_SUITE_GCMP128) { + _libwifi_add_sec_item(buf, &offset, &append, "GCMP128"); + } + if (bss->encryption_info & LIBWIFI_GROUP_CIPHER_SUITE_GCMP256) { + _libwifi_add_sec_item(buf, &offset, &append, "GCMP256"); + } + if (bss->encryption_info & LIBWIFI_GROUP_CIPHER_SUITE_CCMP256) { + _libwifi_add_sec_item(buf, &offset, &append, "CCMP256"); + } + if (bss->encryption_info & LIBWIFI_GROUP_CIPHER_SUITE_BIP_GMAC128) { + _libwifi_add_sec_item(buf, &offset, &append, "BIP_GMAC128"); + } + if (bss->encryption_info & LIBWIFI_GROUP_CIPHER_SUITE_BIP_GMAC256) { + _libwifi_add_sec_item(buf, &offset, &append, "BIP_GMAC256"); + } + if (bss->encryption_info & LIBWIFI_GROUP_CIPHER_SUITE_BIP_CMAC256) { + _libwifi_add_sec_item(buf, &offset, &append, "BIP_CMAC256"); + } +} + +void libwifi_get_pairwise_ciphers(struct libwifi_bss *bss, char *buf) { + memset(buf, 0, LIBWIFI_SECURITY_BUF_LEN); + + int offset = 0; + int append = 0; + + if (bss->encryption_info == 0) { + snprintf(buf + offset, LIBWIFI_SECURITY_BUF_LEN, "None"); + return; + } + + if (bss->encryption_info & LIBWIFI_PAIRWISE_SUITE_GROUP) { + _libwifi_add_sec_item(buf, &offset, &append, "GROUP"); + } + if (bss->encryption_info & LIBWIFI_PAIRWISE_CIPHER_SUITE_WEP40) { + _libwifi_add_sec_item(buf, &offset, &append, "WEP40"); + } + if (bss->encryption_info & LIBWIFI_PAIRWISE_CIPHER_SUITE_TKIP) { + _libwifi_add_sec_item(buf, &offset, &append, "TKIP"); + } + if (bss->encryption_info & LIBWIFI_PAIRWISE_CIPHER_SUITE_RESERVED) { + _libwifi_add_sec_item(buf, &offset, &append, "RESERVED"); + } + if (bss->encryption_info & LIBWIFI_PAIRWISE_CIPHER_SUITE_CCMP128) { + _libwifi_add_sec_item(buf, &offset, &append, "CCMP128"); + } + if (bss->encryption_info & LIBWIFI_PAIRWISE_CIPHER_SUITE_WEP104) { + _libwifi_add_sec_item(buf, &offset, &append, "WEP104"); + } + if (bss->encryption_info & LIBWIFI_PAIRWISE_CIPHER_SUITE_BIP_CMAC128) { + _libwifi_add_sec_item(buf, &offset, &append, "BIP_CMAC128"); + } + if (bss->encryption_info & LIBWIFI_PAIRWISE_CIPHER_SUITE_NOTALLOWED) { + _libwifi_add_sec_item(buf, &offset, &append, "NOT_ALLOWED"); + } + if (bss->encryption_info & LIBWIFI_PAIRWISE_CIPHER_SUITE_GCMP128) { + _libwifi_add_sec_item(buf, &offset, &append, "GCMP128"); + } + if (bss->encryption_info & LIBWIFI_PAIRWISE_CIPHER_SUITE_GCMP256) { + _libwifi_add_sec_item(buf, &offset, &append, "GCMP256"); + } + if (bss->encryption_info & LIBWIFI_PAIRWISE_CIPHER_SUITE_CCMP256) { + _libwifi_add_sec_item(buf, &offset, &append, "CCMP256"); + } + if (bss->encryption_info & LIBWIFI_PAIRWISE_CIPHER_SUITE_BIP_GMAC128) { + _libwifi_add_sec_item(buf, &offset, &append, "BIP_GMAC128"); + } + if (bss->encryption_info & LIBWIFI_PAIRWISE_CIPHER_SUITE_BIP_GMAC256) { + _libwifi_add_sec_item(buf, &offset, &append, "BIP_GMAC256"); + } + if (bss->encryption_info & LIBWIFI_PAIRWISE_CIPHER_SUITE_BIP_CMAC256) { + _libwifi_add_sec_item(buf, &offset, &append, "BIP_CMAC256"); + } +} + +void libwifi_get_auth_key_suites(struct libwifi_bss *bss, char *buf) { + memset(buf, 0, LIBWIFI_SECURITY_BUF_LEN); + + int offset = 0; + int append = 0; + + if (bss->encryption_info == 0) { + snprintf(buf + offset, LIBWIFI_SECURITY_BUF_LEN, "None"); + return; + } + + if (bss->encryption_info & LIBWIFI_AKM_SUITE_RESERVED) { + _libwifi_add_sec_item(buf, &offset, &append, "RESERVED"); + } + if (bss->encryption_info & LIBWIFI_AKM_SUITE_1X) { + _libwifi_add_sec_item(buf, &offset, &append, "802.1X"); + } + if (bss->encryption_info & LIBWIFI_AKM_SUITE_PSK) { + _libwifi_add_sec_item(buf, &offset, &append, "PSK"); + } + if (bss->encryption_info & LIBWIFI_AKM_SUITE_1X_FT) { + _libwifi_add_sec_item(buf, &offset, &append, "802.1X_FT"); + } + if (bss->encryption_info & LIBWIFI_AKM_SUITE_PSK_FT) { + _libwifi_add_sec_item(buf, &offset, &append, "PSK_FT"); + } + if (bss->encryption_info & LIBWIFI_AKM_SUITE_1X_SHA256) { + _libwifi_add_sec_item(buf, &offset, &append, "802.1X_SHA256"); + } + if (bss->encryption_info & LIBWIFI_AKM_SUITE_PSK_SHA256) { + _libwifi_add_sec_item(buf, &offset, &append, "PSK_SHA256"); + } + if (bss->encryption_info & LIBWIFI_AKM_SUITE_TDLS) { + _libwifi_add_sec_item(buf, &offset, &append, "TDLS"); + } + if (bss->encryption_info & LIBWIFI_AKM_SUITE_SAE) { + _libwifi_add_sec_item(buf, &offset, &append, "SAE"); + } + if (bss->encryption_info & LIBWIFI_AKM_SUITE_SAE_FT) { + _libwifi_add_sec_item(buf, &offset, &append, "SAE_FT"); + } + if (bss->encryption_info & LIBWIFI_AKM_SUITE_AP_PEER) { + _libwifi_add_sec_item(buf, &offset, &append, "AP_PEER"); + } + if (bss->encryption_info & LIBWIFI_AKM_SUITE_1X_SUITEB_SHA256) { + _libwifi_add_sec_item(buf, &offset, &append, "802.1X_SUITEB_SHA256"); + } + if (bss->encryption_info & LIBWIFI_AKM_SUITE_1X_SUITEB_SHA384) { + _libwifi_add_sec_item(buf, &offset, &append, "802.1X_SUITEB_SHA384"); + } + if (bss->encryption_info & LIBWIFI_AKM_SUITE_1X_FT_SHA384) { + _libwifi_add_sec_item(buf, &offset, &append, "802.1X_FT_SHA384"); + } + if (bss->encryption_info & LIBWIFI_AKM_SUITE_FILS_SHA256) { + _libwifi_add_sec_item(buf, &offset, &append, "FILS_SHA256"); + } + if (bss->encryption_info & LIBWIFI_AKM_SUITE_FILS_SHA384) { + _libwifi_add_sec_item(buf, &offset, &append, "FILS_SHA384"); + } + if (bss->encryption_info & LIBWIFI_AKM_SUITE_FILS_SHA256_FT) { + _libwifi_add_sec_item(buf, &offset, &append, "FILS_SHA256_FT"); + } + if (bss->encryption_info & LIBWIFI_AKM_SUITE_FILS_SHA384_FT) { + _libwifi_add_sec_item(buf, &offset, &append, "FILS_SHA384_FT"); + } + if (bss->encryption_info & LIBWIFI_AKM_SUITE_OWE) { + _libwifi_add_sec_item(buf, &offset, &append, "OWE"); + } + if (bss->encryption_info & LIBWIFI_AKM_PSK_SHA384_FT) { + _libwifi_add_sec_item(buf, &offset, &append, "PSK_SHA384_FT"); + } + if (bss->encryption_info & LIBWIFI_AKM_PSK_SHA384) { + _libwifi_add_sec_item(buf, &offset, &append, "PSK_SHA384"); + } +} + +void _libwifi_add_sec_item(char *buf, int *offset, int *append, char *item) { + if (*append) { + snprintf(buf + *offset, LIBWIFI_SECURITY_BUF_LEN, ", "); + *offset += strlen(", "); + } + snprintf(buf + *offset, LIBWIFI_SECURITY_BUF_LEN, "%s", item); + *offset += strlen(item); + *append = 1; +} diff --git a/src/libwifi/parse/misc/security.h b/src/libwifi/parse/misc/security.h new file mode 100644 index 0000000..dba2850 --- /dev/null +++ b/src/libwifi/parse/misc/security.h @@ -0,0 +1,124 @@ +/* Copyright 2021 The libwifi Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBWIFI_PARSE_SECURITY_H +#define LIBWIFI_PARSE_SECURITY_H + +#include "../../core/frame/management/common.h" +#include "../../core/misc/security.h" + +#include + +#define LIBWIFI_SECURITY_BUF_LEN 256 + +/** + * Get the RSN related information and store it in a + * libwifi_rsn_info. This function will detect and enumerate + * cipher suites, and AKM suites, and the RSN capabilities + * from a specified RSN IE. + * + * @param info A libwifi_rsn_info + * @param tag_data An RSN IE tag + * @param tag_end The end of the specified RSN IE tag + * @return + */ +int libwifi_get_rsn_info(struct libwifi_rsn_info *info, const unsigned char *tag_data, + const unsigned char *tag_end); + +/** + * Enumerate the RSN cipher suites in a libwifi_rsn_info. + * + * This function can be used to fill a libwifi_bss struct + * with information related to the cipher suites and AKM suites + * in the specified libwifi_rsn_info. + * + * @param rsn_info A libwifi_rsn_info + * @param libwifi_bss A libwifi_bss + */ +void libwifi_enumerate_rsn_suites(struct libwifi_rsn_info *rsn_info, struct libwifi_bss *bss); + +/** + * Get the WPA related information and store it in a + * libwifi_wpa_info. This function will detect and enumerate + * cipher suites and AKM suites from a specified WPA IE. + * + * @param info A libwifi_wpa_info + * @param tag_data A WPA IE tag + * @param tag_end The end of the specified WPA IE tag + * @return + */ +int libwifi_get_wpa_info(struct libwifi_wpa_info *info, const unsigned char *tag_data, + const unsigned char *tag_end); + +/** + * Enumerate the WPA cipher suites in a libwifi_wpa_info. + * + * This function can be used to fill a libwifi_bss struct + * with information related to the cipher suites and AKM suites + * in the specified libwifi_wpa_info. + * + * @param wpa_info A libwifi_wpa_info + * @param libwifi_bss A libwifi_bss + */ +void libwifi_enumerate_wpa_suites(struct libwifi_wpa_info *wpa_info, struct libwifi_bss *bss); + +/** + * Enumerate the security types (WEP, WPA, WPA2, WPA3, etc) in a given libwifi_bss, + * formatted into the given buffer. + * + * @param bss A libwifi_bss struct + * @param buf A buffer of length LIBWIFI_SECURITY_BUF_LEN + */ +void libwifi_get_security_type(struct libwifi_bss *bss, char *buf); + +/** + * Enumerate the group ciphers (CCMP, GCMP128, etc) in a given libwifi_bss, + * formatted into the given buffer. + * + * @param bss A libwifi_bss struct + * @param buf A buffer of length LIBWIFI_SECURITY_BUF_LEN + */ +void libwifi_get_group_ciphers(struct libwifi_bss *bss, char *buf); + +/** + * Enumerate the pairwise ciphers (GROUP, CCMP, BIP_CMAC128, etc) in a given libwifi_bss, + * formatted into the given buffer. + * + * @param bss A libwifi_bss struct + * @param buf A buffer of length LIBWIFI_SECURITY_BUF_LEN + */ +void libwifi_get_pairwise_ciphers(struct libwifi_bss *bss, char *buf); + +/** + * Enumerate the auth key management suites in a given libwifi_bss, + * formatted into the given buffer. + * + * @param bss A libwifi_bss struct + * @param buf A buffer of length LIBWIFI_SECURITY_BUF_LEN + */ +void libwifi_get_auth_key_suites(struct libwifi_bss *bss, char *buf); + +/** + * Internal function for adding a formatted string to a buffer for use with + * libwifi_get_* security functions. + * + * @param buf A buffer of length LIBWIFI_SECURITY_BUF_LEN + * @param offset A pointer to the current buffer offset variable + * @param append A pointer to the append state variable + * @param item A pointer to the string to append to the given buf + */ +void _libwifi_add_sec_item(char *buf, int *offset, int *append, char *item); + +#endif /* LIBWIFI_PARSE_SECURITY_H */ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..b418f93 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.18) + +project(libwifi_tests VERSION 0.1) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED True) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ggdb -O0") + +add_executable(test_misc src/helpers.c src/test_misc.c) +add_executable(test_generation src/helpers.c src/test_generation.c) +add_executable(test_parsing src/helpers.c src/test_parsing.c) + +target_link_libraries(test_misc wifi) +target_link_libraries(test_generation wifi pcap) +target_link_libraries(test_parsing wifi pcap) diff --git a/test/pcaps/assoc_req.pcap b/test/pcaps/assoc_req.pcap new file mode 100644 index 0000000..87ad19b Binary files /dev/null and b/test/pcaps/assoc_req.pcap differ diff --git a/test/pcaps/assoc_resp.pcap b/test/pcaps/assoc_resp.pcap new file mode 100644 index 0000000..16f6fad Binary files /dev/null and b/test/pcaps/assoc_resp.pcap differ diff --git a/test/pcaps/auth.pcap b/test/pcaps/auth.pcap new file mode 100644 index 0000000..e667432 Binary files /dev/null and b/test/pcaps/auth.pcap differ diff --git a/test/pcaps/beacons_with_221.pcap b/test/pcaps/beacons_with_221.pcap new file mode 100644 index 0000000..5cc20ff Binary files /dev/null and b/test/pcaps/beacons_with_221.pcap differ diff --git a/test/pcaps/deauth.pcap b/test/pcaps/deauth.pcap new file mode 100644 index 0000000..c8fb77c Binary files /dev/null and b/test/pcaps/deauth.pcap differ diff --git a/test/pcaps/deauth_with_221.pcap b/test/pcaps/deauth_with_221.pcap new file mode 100644 index 0000000..ba53dd1 Binary files /dev/null and b/test/pcaps/deauth_with_221.pcap differ diff --git a/test/pcaps/disassoc.pcap b/test/pcaps/disassoc.pcap new file mode 100644 index 0000000..f217150 Binary files /dev/null and b/test/pcaps/disassoc.pcap differ diff --git a/test/pcaps/probe_req.pcap b/test/pcaps/probe_req.pcap new file mode 100644 index 0000000..b039e4b Binary files /dev/null and b/test/pcaps/probe_req.pcap differ diff --git a/test/pcaps/probe_resp_with_221.pcap b/test/pcaps/probe_resp_with_221.pcap new file mode 100644 index 0000000..3d664b0 Binary files /dev/null and b/test/pcaps/probe_resp_with_221.pcap differ diff --git a/test/pcaps/reassoc_req.pcap b/test/pcaps/reassoc_req.pcap new file mode 100644 index 0000000..f5bd99e Binary files /dev/null and b/test/pcaps/reassoc_req.pcap differ diff --git a/test/pcaps/reassoc_resp.pcap b/test/pcaps/reassoc_resp.pcap new file mode 100644 index 0000000..c3e657f Binary files /dev/null and b/test/pcaps/reassoc_resp.pcap differ diff --git a/test/src/.clang-format b/test/src/.clang-format new file mode 100644 index 0000000..111249f --- /dev/null +++ b/test/src/.clang-format @@ -0,0 +1,8 @@ +--- +BasedOnStyle: LLVM +IndentWidth: '4' +SpaceAfterCStyleCast: 'true' +ColumnLimit: 400 +AllowShortFunctionsOnASingleLine: None +IndentCaseLabels: 'true' +... diff --git a/test/src/helpers.c b/test/src/helpers.c new file mode 100644 index 0000000..9fc9d0b --- /dev/null +++ b/test/src/helpers.c @@ -0,0 +1,31 @@ +#include "helpers.h" +#include + +void hexdump(void *data, size_t size) { + char ascii[17]; + size_t i, j; + ascii[16] = '\0'; + for (i = 0; i < size; ++i) { + printf("%02X ", ((unsigned char *) data)[i]); + if (((unsigned char *) data)[i] >= ' ' && ((unsigned char *) data)[i] <= '~') { + ascii[i % 16] = ((unsigned char *) data)[i]; + } else { + ascii[i % 16] = '.'; + } + if ((i + 1) % 8 == 0 || i + 1 == size) { + printf(" "); + if ((i + 1) % 16 == 0) { + printf("| %s \n", ascii); + } else if (i + 1 == size) { + ascii[(i + 1) % 16] = '\0'; + if ((i + 1) % 16 <= 8) { + printf(" "); + } + for (j = (i + 1) % 16; j < 16; ++j) { + printf(" "); + } + printf("| %s \n", ascii); + } + } + } +} diff --git a/test/src/helpers.h b/test/src/helpers.h new file mode 100644 index 0000000..99a5329 --- /dev/null +++ b/test/src/helpers.h @@ -0,0 +1,60 @@ +#include +#include + +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" + +static const uint8_t radiotap_data[] = { + 0x00, + 0x00, // <-- radiotap version (ignore this) + 0x18, + 0x00, // <-- number of bytes in our header (count the number of "0x"s) + + /** + * The next field is a bitmap of which options we are including. + * The full list of which field is which option is in ieee80211_radiotap.h, + * but I've chosen to include: + * 0x00 0x01: timestamp + * 0x00 0x02: flags + * 0x00 0x03: rate + * 0x00 0x04: channel + * 0x80 0x00: tx flags (seems silly to have this AND flags, but oh well) + */ + 0x0f, + 0x80, + 0x00, + 0x00, + + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, + 0x00, // <-- timestamp + + /** + * This is the first set of flags, and we've set the bit corresponding to + * IEEE80211_RADIOTAP_F_FCS, meaning we want the card to add a FCS at the + * end of our buffer for us. + */ + 0x10, + + 0x00, // <-- rate + 0x00, + 0x00, + 0x00, + 0x00, // <-- channel + + /** + * This is the second set of flags, specifically related to transmissions. + * The bit we've set is IEEE80211_RADIOTAP_F_TX_NOACK, which means the card + * won't wait for an ACK for this frame, and that it won't retry if it + * doesn't get one. + */ + 0x08, + 0x00, +}; + +void hexdump(void *data, size_t size); diff --git a/test/src/test_generation.c b/test/src/test_generation.c new file mode 100644 index 0000000..407e87f --- /dev/null +++ b/test/src/test_generation.c @@ -0,0 +1,924 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "helpers.h" + +#define LIVE_INJECT 0 +#define OFFLINE_DUMP 1 + +#define MODE_BEACON 0 +#define MODE_PROBE_RESPONSE 1 +#define MODE_PROBE_REQUEST 2 +#define MODE_DEAUTH 3 +#define MODE_DISASSOC 4 +#define MODE_ASSOC_RESPONSE 5 +#define MODE_ASSOC_REQUEST 6 +#define MODE_REASSOC_RESPONSE 7 +#define MODE_REASSOC_REQUEST 8 +#define MODE_AUTH 9 +#define MODE_RTS 10 +#define MODE_CTS 11 +#define MODE_RANDOM_BEACON 12 +#define MODE_ACTION 13 +#define MODE_ACTION_NOACK 14 +#define MODE_TIMING_AD 15 +#define MODE_ATIM 16 + +#define SNAPLEN 96 +#define CHANNEL 11 +#define BCAST_MAC "\xff\xff\xff\xff\xff\xff" +#define TO_MAC "\x00\x20\x91\xAA\xBB\xCC" +#define FROM_MAC "\x00\x20\x91\x11\x22\x33" +#define REASSOC_MAC "\xAA\xBB\xCC\xDD\xEE\xFF" +#define BEACON_SSID "libwifi-beacon" +#define PROBE_RESP_SSID "libwifi-probe-resp" +#define PROBE_REQ_SSID "libwifi-probe-req" +#define ASSOC_REQ_SSID "libwifi-assoc-req" +#define REASSOC_REQ_SSID "libwifi-reassoc-req" + +pcap_t *handle = NULL; +pcap_dumper_t *outputHandle = NULL; +FILE *filename = NULL; + +static unsigned char to[] = TO_MAC; +static unsigned char from[] = FROM_MAC; +static unsigned char bcast[] = BCAST_MAC; +static unsigned char reassoc_mac[] = REASSOC_MAC; +static unsigned char tag_data[] = "\x00\x00\00\x01This is a 221 tag from libwifi.\n"; + +static int mode = 0; +static int inject_mode = 0; + +void handle_interupt(int signal) { + if (signal == SIGINT) { + int oldmode = inject_mode; + mode = -1; + inject_mode = -1; + + if (oldmode == LIVE_INJECT) { + pcap_close(handle); + printf("\n\nClosed Capture Handle!\n"); + } else if (oldmode == OFFLINE_DUMP) { + pcap_dump_flush(outputHandle); + pcap_dump_close(outputHandle); + printf("\n\nDumped and Closed Output File!\n"); + } + + exit(EXIT_SUCCESS); + } +} + +void inject_frame(void *buf, size_t buf_sz) { + struct libwifi_radiotap_info info = {0}; + info.present = 0x0000002e; // 0x002e: Flags, Rate, Channel, dBm Ant Signal + info.channel.flags = 0x0140; // OFDM, 5GHz + info.channel.freq = 5180; // Channel 46 + info.flags = 0x0000; // No Flags + info.rate = 1; // 1 Mbit + info.rate_raw = info.rate * 2; // Radiotap uses 500kb/s increments + info.signal = -20; // Signal in dBm + + char *rtap = NULL; + rtap = malloc(LIBWIFI_MAX_RADIOTAP_LEN); + if (rtap == NULL) { + printf("malloc failure: %s\n", strerror(errno)); + return; + } + memset(rtap, 0, LIBWIFI_MAX_RADIOTAP_LEN); + + int rtap_len = libwifi_create_radiotap(&info, rtap); + if (rtap_len == -1) { + printf("error generating radiotap header\n"); + return; + } + + void *frame = NULL; + size_t frame_sz = rtap_len + buf_sz; + frame = malloc(frame_sz); + if (frame == NULL) { + printf("malloc failure: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + memcpy(frame, rtap, rtap_len); + memcpy(frame + rtap_len, buf, buf_sz); + + hexdump(rtap, rtap_len); + printf("-----\n"); + hexdump(frame, frame_sz); + + if (inject_mode == LIVE_INJECT) { + pcap_inject(handle, frame, frame_sz); + } else if (inject_mode == OFFLINE_DUMP) { + struct pcap_pkthdr hdr = {0}; + hdr.caplen = frame_sz; + hdr.len = frame_sz; + struct timeval tv; + gettimeofday(&tv, NULL); + hdr.ts = tv; + pcap_dump((unsigned char *) outputHandle, &hdr, frame); + } + + free(rtap); + free(frame); +} + +void inject_beacons(int random_mac) { + while (1) { + printf("Sending 50 beacons...\n"); + for (int i = 0; i < 50; ++i) { + struct libwifi_beacon beacon; + unsigned char txmac[6] = {0}; + memset(&beacon, 0, sizeof(struct libwifi_beacon)); + + if (random_mac) { + libwifi_random_mac(txmac, NULL); + } else { + memcpy(txmac, FROM_MAC, 6); + } + libwifi_create_beacon(&beacon, bcast, txmac, BEACON_SSID, CHANNEL); + libwifi_quick_add_tag(&beacon.tags, TAG_VENDOR_SPECIFIC, tag_data, sizeof(tag_data)); + + unsigned char *buf = NULL; + size_t buf_sz = libwifi_get_beacon_length(&beacon); + + buf = malloc(buf_sz); + if (buf == NULL) { + printf("malloc failure: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + printf("Injecting beacon with:\n"); + printf("\tSSID: %s\n", BEACON_SSID); + printf("\tChannel: %d\n", CHANNEL); + printf("\tSource: " MACSTR "\n", MAC2STR(txmac)); + printf("\tDestination: " MACSTR "\n", MAC2STR(bcast)); + + libwifi_dump_beacon(&beacon, buf, buf_sz); + inject_frame(buf, buf_sz); + + libwifi_free_beacon(&beacon); + free(buf); + usleep(1e4); // 10ms + } + sleep(1); + } +} + +void inject_probe_responses() { + while (1) { + printf("Sending 50 probe responses, then sleeping for 1 second\n"); + for (int i = 0; i < 50; ++i) { + struct libwifi_probe_resp probe_resp; + memset(&probe_resp, 0, sizeof(struct libwifi_probe_resp)); + + libwifi_create_probe_resp(&probe_resp, to, from, PROBE_RESP_SSID, CHANNEL); + libwifi_quick_add_tag(&probe_resp.tags, TAG_VENDOR_SPECIFIC, tag_data, sizeof(tag_data)); + + unsigned char *buf = NULL; + size_t buf_sz = libwifi_get_probe_resp_length(&probe_resp); + + buf = malloc(buf_sz); + if (buf == NULL) { + printf("malloc failure: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + printf("Injecting probe responses with:\n"); + printf("\tSSID: %s\n", PROBE_RESP_SSID); + printf("\tChannel: %d\n", CHANNEL); + printf("\tSource: " MACSTR "\n", MAC2STR(from)); + printf("\tDestination: " MACSTR "\n", MAC2STR(to)); + + libwifi_dump_probe_resp(&probe_resp, buf, buf_sz); + inject_frame(buf, buf_sz); + + libwifi_free_probe_resp(&probe_resp); + free(buf); + usleep(1e4); // 10ms + } + sleep(1); + } +} + +void inject_probe_requests() { + while (1) { + printf("Sending 50 probe responses, then sleeping for 1 second\n"); + for (int i = 0; i < 50; ++i) { + struct libwifi_probe_req probe; + memset(&probe, 0, sizeof(struct libwifi_probe_req)); + + libwifi_create_probe_req(&probe, to, from, to, PROBE_REQ_SSID, CHANNEL); + + unsigned char *buf = NULL; + size_t buf_sz = libwifi_get_probe_req_length(&probe); + + buf = malloc(buf_sz); + if (buf == NULL) { + printf("malloc failure: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + printf("Injecting probe requests with:\n"); + printf("\tSSID: %s\n", PROBE_REQ_SSID); + printf("\tChannel: %d\n", CHANNEL); + printf("\tSource: " MACSTR "\n", MAC2STR(from)); + printf("\tDestination: " MACSTR "\n", MAC2STR(to)); + + libwifi_dump_probe_req(&probe, buf, buf_sz); + inject_frame(buf, buf_sz); + + libwifi_free_probe_req(&probe); + free(buf); + + usleep(1e4); // 10ms + } + sleep(1); + } +} + +void inject_deauths() { + while (1) { + printf("Sending 50 probe responses, then sleeping for 1 second\n"); + for (int i = 0; i < 50; ++i) { + struct libwifi_deauth deauth; + memset(&deauth, 0, sizeof(struct libwifi_deauth)); + + libwifi_create_deauth(&deauth, to, from, REASON_STA_LEAVING); + + unsigned char *buf = NULL; + size_t buf_sz = libwifi_get_deauth_length(&deauth); + + buf = malloc(buf_sz); + if (buf == NULL) { + printf("malloc failure: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + printf("Injecting deauths with:\n"); + printf("\tChannel: %d\n", CHANNEL); + printf("\tReason: %d\n", REASON_STA_LEAVING); + printf("\tSource: " MACSTR "\n", MAC2STR(from)); + printf("\tDestination: " MACSTR "\n", MAC2STR(to)); + + libwifi_dump_deauth(&deauth, buf, buf_sz); + inject_frame(buf, buf_sz); + + free(buf); + + usleep(1e4); // 10ms + } + sleep(1); + } +} + +void inject_disassocs() { + while (1) { + printf("Sending 50 probe responses, then sleeping for 1 second\n"); + for (int i = 0; i < 50; ++i) { + struct libwifi_disassoc disassoc; + memset(&disassoc, 0, sizeof(struct libwifi_disassoc)); + + libwifi_create_disassoc(&disassoc, to, from, REASON_STA_LEAVING); + + unsigned char *buf = NULL; + size_t buf_sz = libwifi_get_disassoc_length(&disassoc); + + buf = malloc(buf_sz); + if (buf == NULL) { + printf("malloc failure: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + printf("Injecting disassocs with:\n"); + printf("\tChannel: %d\n", CHANNEL); + printf("\tReason: %d\n", REASON_STA_LEAVING); + printf("\tSource: " MACSTR "\n", MAC2STR(from)); + printf("\tDestination: " MACSTR "\n", MAC2STR(to)); + + libwifi_dump_disassoc(&disassoc, buf, buf_sz); + inject_frame(buf, buf_sz); + + free(buf); + + usleep(1e4); // 10ms + } + sleep(1); + } +} + +void inject_assoc_requests() { + while (1) { + printf("Sending 50 association requests, then sleeping for 1 second\n"); + for (int i = 0; i < 50; ++i) { + struct libwifi_assoc_req assoc_req; + memset(&assoc_req, 0, sizeof(struct libwifi_assoc_req)); + + libwifi_create_assoc_req(&assoc_req, to, from, ASSOC_REQ_SSID, CHANNEL); + + unsigned char *buf = NULL; + size_t buf_sz = libwifi_get_assoc_req_length(&assoc_req); + + buf = malloc(buf_sz); + if (buf == NULL) { + printf("malloc failure: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + printf("Injecting association requests with:\n"); + printf("\tChannel: %d\n", CHANNEL); + printf("\tSource: " MACSTR "\n", MAC2STR(from)); + printf("\tDestination: " MACSTR "\n", MAC2STR(to)); + + libwifi_dump_assoc_req(&assoc_req, buf, buf_sz); + inject_frame(buf, buf_sz); + + free(buf); + libwifi_free_assoc_req(&assoc_req); + + usleep(1e4); // 10ms + } + sleep(1); + } +} + +void inject_assoc_responses() { + while (1) { + printf("Sending 50 association responses, then sleeping for 1 second\n"); + for (int i = 0; i < 50; ++i) { + struct libwifi_assoc_resp assoc_resp; + memset(&assoc_resp, 0, sizeof(struct libwifi_assoc_req)); + + libwifi_create_assoc_resp(&assoc_resp, to, from, CHANNEL); + + unsigned char *buf = NULL; + size_t buf_sz = libwifi_get_assoc_resp_length(&assoc_resp); + + buf = malloc(buf_sz); + if (buf == NULL) { + printf("malloc failure: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + printf("Injecting association responses with:\n"); + printf("\tChannel: %d\n", CHANNEL); + printf("\tSource: " MACSTR "\n", MAC2STR(from)); + printf("\tDestination: " MACSTR "\n", MAC2STR(to)); + + libwifi_dump_assoc_resp(&assoc_resp, buf, buf_sz); + inject_frame(buf, buf_sz); + + free(buf); + libwifi_free_assoc_resp(&assoc_resp); + + usleep(1e4); // 10ms + } + sleep(1); + } +} + +void inject_reassoc_requests() { + while (1) { + printf("Sending 50 reassociation requests, then sleeping for 1 second\n"); + for (int i = 0; i < 50; ++i) { + struct libwifi_reassoc_req reassoc_req; + memset(&reassoc_req, 0, sizeof(struct libwifi_assoc_req)); + + libwifi_create_reassoc_req(&reassoc_req, to, from, reassoc_mac, REASSOC_REQ_SSID, CHANNEL); + + unsigned char *buf = NULL; + size_t buf_sz = libwifi_get_reassoc_req_length(&reassoc_req); + + buf = malloc(buf_sz); + if (buf == NULL) { + printf("malloc failure: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + printf("Injecting reassociation requests with:\n"); + printf("\tChannel: %d\n", CHANNEL); + printf("\tSource: " MACSTR "\n", MAC2STR(from)); + printf("\tDestination: " MACSTR "\n", MAC2STR(to)); + printf("\tPrevious BSSID: " MACSTR "\n", MAC2STR(reassoc_mac)); + + libwifi_dump_reassoc_req(&reassoc_req, buf, buf_sz); + inject_frame(buf, buf_sz); + + free(buf); + libwifi_free_reassoc_req(&reassoc_req); + + usleep(1e4); // 10ms + } + sleep(1); + } +} + +void inject_reassoc_responses() { + while (1) { + printf("Sending 50 reassociation responses, then sleeping for 1 second\n"); + for (int i = 0; i < 50; ++i) { + struct libwifi_reassoc_resp reassoc_resp; + memset(&reassoc_resp, 0, sizeof(struct libwifi_assoc_req)); + + libwifi_create_reassoc_resp(&reassoc_resp, to, from, CHANNEL); + + unsigned char *buf = NULL; + size_t buf_sz = libwifi_get_reassoc_resp_length(&reassoc_resp); + + buf = malloc(buf_sz); + if (buf == NULL) { + printf("malloc failure: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + printf("Injecting reassociation responses with:\n"); + printf("\tChannel: %d\n", CHANNEL); + printf("\tSource: " MACSTR "\n", MAC2STR(from)); + printf("\tDestination: " MACSTR "\n", MAC2STR(to)); + + libwifi_dump_reassoc_resp(&reassoc_resp, buf, buf_sz); + inject_frame(buf, buf_sz); + + free(buf); + libwifi_free_reassoc_resp(&reassoc_resp); + + usleep(1e4); // 10ms + } + sleep(1); + } +} + +void inject_auths() { + while (1) { + printf("Sending 50 auth frames, then sleeping for 1 second\n"); + for (int i = 0; i < 50; ++i) { + struct libwifi_auth auth; + memset(&auth, 0, sizeof(struct libwifi_deauth)); + + libwifi_create_auth(&auth, to, from, AUTH_OPEN, 0, STATUS_SUCCESS); + + unsigned char *buf = NULL; + size_t buf_sz = libwifi_get_auth_length(&auth); + + buf = malloc(buf_sz); + if (buf == NULL) { + printf("malloc failure: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + libwifi_dump_auth(&auth, buf, buf_sz); + inject_frame(buf, buf_sz); + + free(buf); + + memset(&auth, 0, sizeof(struct libwifi_deauth)); + + libwifi_create_auth(&auth, from, to, AUTH_OPEN, 1, STATUS_SUCCESS); + + buf = NULL; + buf_sz = libwifi_get_auth_length(&auth); + + buf = malloc(buf_sz); + if (buf == NULL) { + printf("malloc failure: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + printf("Injecting auths with:\n"); + printf("\tChannel: %d\n", CHANNEL); + printf("\tAlgorithm: %d\n", AUTH_OPEN); + printf("\tSource: " MACSTR "\n", MAC2STR(from)); + printf("\tDestination: " MACSTR "\n", MAC2STR(to)); + + libwifi_dump_auth(&auth, buf, buf_sz); + inject_frame(buf, buf_sz); + + free(buf); + usleep(1e4); // 10ms + } + sleep(1); + } +} + +void inject_timing_ads() { + while (1) { + printf("Sending 50 timing advertisement frames, then sleeping for 1 second\n"); + for (int i = 0; i < 50; ++i) { + struct libwifi_timing_advert time_ad = {0}; + struct libwifi_timing_advert_fields ad_fields = {0}; + + ad_fields.timing_capabilities = 2; + memcpy(ad_fields.time_error, "\xCC\xCC\xCC\xCC\xCC", 5); + memcpy(ad_fields.time_update, "\xBB", 1); + memcpy(ad_fields.time_value, + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA", 10); + + libwifi_create_timing_advert(&time_ad, to, from, &ad_fields, "GB", -56, -56, -30, -20); + + unsigned char *buf = NULL; + size_t buf_len = libwifi_get_timing_advert_length(&time_ad); + buf = malloc(buf_len); + if (buf == NULL) { + printf("malloc failure: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + printf("buf_len: %zu\n", buf_len); + + size_t ret = libwifi_dump_timing_advert(&time_ad, buf, buf_len); + if (ret < 0) { + printf("error dump: %zu\n", ret); + exit(EXIT_FAILURE); + } + hexdump(buf, buf_len); + inject_frame(buf, buf_len); + + free(buf); + libwifi_free_timing_advert(&time_ad); + + usleep(1e4); // 10ms + } + sleep(1); + } +} + +void inject_action_noacks() { + while (1) { + printf("Sending 50 action no ack frames, then sleeping for 1 second\n"); + for (int i = 0; i < 50; ++i) { + struct libwifi_action action; + memset(&action, 0, sizeof(struct libwifi_action)); + + libwifi_create_action_no_ack(&action, to, from, ACTION_FAST_BSS_TRANSITION); + + unsigned char *action_buf = malloc(256); + memset(action_buf, 0, 256); + + size_t offset = 0; + size_t w = 0; + + memcpy(action_buf, "\x01", 1); // Fast BSS Request + offset += 1; + memcpy(action_buf + offset, "\xAA\xBB\xCC\xDD\xEE\xFF", 6); // STA Address + offset += 6; + memcpy(action_buf + offset, "\xFF\xEE\xDD\xCC\xBB\xAA", 6); // AP Address + offset += 6; + + unsigned char *tag_tmp = malloc(256); + memset(tag_tmp, 0, 256); + + struct libwifi_tagged_parameter rsne = {0}; + size_t tsz = libwifi_create_tag(&rsne, TAG_RSN, (const unsigned char * )"\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x02\x00\x00", 20); + w = libwifi_dump_tag(&rsne, tag_tmp, tsz); + memcpy(action_buf + offset, tag_tmp, w); + offset += w; + + + struct libwifi_tagged_parameter mobdom = {0}; + tsz = libwifi_create_tag(&mobdom, TAG_MOBILITY_DOMAIN, (const unsigned char*)"\x00\x11\x01", 3); + memset(tag_tmp, 0, tsz); + w = libwifi_dump_tag(&mobdom, tag_tmp, tsz); + memcpy(action_buf + offset, tag_tmp, w); + offset += w; + libwifi_free_tag(&mobdom); + + struct libwifi_tagged_parameter fbss = {0}; + tsz = libwifi_create_tag(&fbss, TAG_FAST_BSS_TRANSITION, (const unsigned char*)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xAA\xBB\xCC\xDD\xEE\xFF\xAA\xBB\xCC\xDD\xEE\xFF\xAA\xBB\xCC\xDD\xEE\xFF\xAA\xBB\xCC\xDD\xEE\xFF\xAA\xBB\xCC\xDD\xEE\xFF\xAA\x03\x04\xAA\xBB\x04\xAA\xBB\xCC\xDD", 88); + memset(tag_tmp, 0, tsz); + w = libwifi_dump_tag(&fbss, tag_tmp, tsz); + memcpy(action_buf + offset, tag_tmp, w); + offset += w; + libwifi_free_tag(&fbss); + + libwifi_add_action_detail(&action.fixed_parameters.details, action_buf, offset); + + unsigned char *buf = NULL; + size_t buf_sz = libwifi_get_action_length(&action); + + buf = malloc(buf_sz); + if (buf == NULL) { + printf("malloc failure: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + printf("Injecting actions with:\n"); + printf("\tAction: %d\n", ACTION_FAST_BSS_TRANSITION); + printf("\tSource: " MACSTR "\n", MAC2STR(from)); + printf("\tDestination: " MACSTR "\n", MAC2STR(to)); + + libwifi_dump_action(&action, buf, buf_sz); + inject_frame(buf, buf_sz); + + free(buf); + + usleep(1e4); // 10ms + } + sleep(1); + } +} + +void inject_actions() { + while (1) { + printf("Sending 50 action frames, then sleeping for 1 second\n"); + for (int i = 0; i < 50; ++i) { + struct libwifi_action action; + memset(&action, 0, sizeof(struct libwifi_action)); + + libwifi_create_action(&action, to, from, ACTION_FAST_BSS_TRANSITION); + + unsigned char *action_buf = malloc(256); + memset(action_buf, 0, 256); + + size_t offset = 0; + size_t w = 0; + + memcpy(action_buf, "\x01", 1); // Fast BSS Request + offset += 1; + memcpy(action_buf + offset, "\xAA\xBB\xCC\xDD\xEE\xFF", 6); // STA Address + offset += 6; + memcpy(action_buf + offset, "\xFF\xEE\xDD\xCC\xBB\xAA", 6); // AP Address + offset += 6; + + unsigned char *tag_tmp = malloc(256); + memset(tag_tmp, 0, 256); + + struct libwifi_tagged_parameter rsne = {0}; + size_t tsz = libwifi_create_tag(&rsne, TAG_RSN, (const unsigned char * )"\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x04\x01\x00\x00\x0f\xac\x02\x00\x00", 20); + w = libwifi_dump_tag(&rsne, tag_tmp, tsz); + memcpy(action_buf + offset, tag_tmp, w); + offset += w; + + + struct libwifi_tagged_parameter mobdom = {0}; + tsz = libwifi_create_tag(&mobdom, TAG_MOBILITY_DOMAIN, (const unsigned char*)"\x00\x11\x01", 3); + memset(tag_tmp, 0, tsz); + w = libwifi_dump_tag(&mobdom, tag_tmp, tsz); + memcpy(action_buf + offset, tag_tmp, w); + offset += w; + libwifi_free_tag(&mobdom); + + struct libwifi_tagged_parameter fbss = {0}; + tsz = libwifi_create_tag(&fbss, TAG_FAST_BSS_TRANSITION, (const unsigned char*)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xAA\xBB\xCC\xDD\xEE\xFF\xAA\xBB\xCC\xDD\xEE\xFF\xAA\xBB\xCC\xDD\xEE\xFF\xAA\xBB\xCC\xDD\xEE\xFF\xAA\xBB\xCC\xDD\xEE\xFF\xAA\x03\x04\xAA\xBB\x04\xAA\xBB\xCC\xDD", 88); + memset(tag_tmp, 0, tsz); + w = libwifi_dump_tag(&fbss, tag_tmp, tsz); + memcpy(action_buf + offset, tag_tmp, w); + offset += w; + libwifi_free_tag(&fbss); + + libwifi_add_action_detail(&action.fixed_parameters.details, action_buf, offset); + + unsigned char *buf = NULL; + size_t buf_sz = libwifi_get_action_length(&action); + + buf = malloc(buf_sz); + if (buf == NULL) { + printf("malloc failure: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + printf("Injecting actions with:\n"); + printf("\tAction: %d\n", ACTION_FAST_BSS_TRANSITION); + printf("\tSource: " MACSTR "\n", MAC2STR(from)); + printf("\tDestination: " MACSTR "\n", MAC2STR(to)); + + libwifi_dump_action(&action, buf, buf_sz); + inject_frame(buf, buf_sz); + + free(buf); + + usleep(1e4); // 10ms + } + sleep(1); + } +} + +void inject_atim() { + while (1) { + printf("Sending 50 ATIM frames, then sleeping for 1 second\n"); + for (int i = 0; i < 50; ++i) { + struct libwifi_atim atim = {0}; + + libwifi_create_atim(&atim, to, from, from); + + inject_frame(&atim, sizeof(struct libwifi_atim)); + + usleep(1e4); // 10ms + } + sleep(1); + } +} + +void inject_rts() { + while (1) { + printf("Sending 50 RTS frames, then sleeping for 1 second\n"); + for (int i = 0; i < 50; ++i) { + struct libwifi_rts rts = {0}; + + libwifi_create_rts(&rts, to, from, 32); + + inject_frame(&rts, sizeof(struct libwifi_rts)); + + usleep(1e4); // 10ms + } + sleep(1); + } +} + +void inject_cts() { + while (1) { + printf("Sending 50 CTS frames, then sleeping for 1 second\n"); + for (int i = 0; i < 50; ++i) { + struct libwifi_cts cts = {0}; + + libwifi_create_cts(&cts, to, 32); + + inject_frame(&cts, sizeof(struct libwifi_cts)); + + usleep(1e4); // 10ms + } + sleep(1); + } +} + +void help(const char *name) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\t%s --interface [interface] [--mode]\n", name); + fprintf(stderr, "\t\tor\n"); + fprintf(stderr, "\t%s --file [output file] [--mode]\n", name); + fprintf(stderr, "\n"); + fprintf(stderr, "Modes:\n"); + fprintf(stderr, "\t--beacon\n"); + fprintf(stderr, "\t--random-beacon\n"); + fprintf(stderr, "\t--probe-req\n"); + fprintf(stderr, "\t--probe-resp\n"); + fprintf(stderr, "\t--deauth\n"); + fprintf(stderr, "\t--disassoc\n"); + fprintf(stderr, "\t--assoc-req\n"); + fprintf(stderr, "\t--assoc-resp\n"); + fprintf(stderr, "\t--reassoc-req\n"); + fprintf(stderr, "\t--reassoc-resp\n"); + fprintf(stderr, "\t--auth\n"); + fprintf(stderr, "\t--timing-ad\n"); + fprintf(stderr, "\t--atim\n"); + fprintf(stderr, "\t--rts\n"); + fprintf(stderr, "\t--cts\n"); +} + +void handle_args(int argc, const char *argv[]) { + char errbuf[PCAP_ERRBUF_SIZE]; + memset(errbuf, 0, PCAP_ERRBUF_SIZE); + + if (argc < 4) { + help(argv[0]); + exit(EXIT_SUCCESS); + } + + if (strcmp(argv[1], "--file") == 0) { + inject_mode = OFFLINE_DUMP; + + filename = fopen(argv[2], "w+"); + if ((handle = pcap_open_dead(DLT_IEEE802_11_RADIO, BUFSIZ)) == NULL) { + fprintf(stderr, "1 %s: %s\n", argv[2], errbuf); + exit(EXIT_FAILURE); + } + if ((outputHandle = pcap_dump_fopen(handle, filename)) == NULL) { + fprintf(stderr, "2 %s: %s\n", argv[2], errbuf); + exit(EXIT_FAILURE); + } + } else if (strcmp(argv[1], "--interface") == 0) { + inject_mode = LIVE_INJECT; + + if ((handle = pcap_create(argv[2], errbuf)) == NULL) { + fprintf(stderr, "Couldn't open interface %s: %s\n", argv[2], errbuf); + exit(EXIT_FAILURE); + } + if (pcap_activate(handle) == 0) { + printf("Sniffing on %s\n", argv[2]); + } else { + fprintf(stderr, "Couldn't activate %s: %s\n", argv[2], pcap_geterr(handle)); + exit(EXIT_FAILURE); + } + } else { + help(argv[0]); + exit(EXIT_SUCCESS); + } + + if (strcmp(argv[3], "--beacon") == 0) { + mode = MODE_BEACON; + } else if (strcmp(argv[3], "--random-beacon") == 0) { + mode = MODE_RANDOM_BEACON; + } else if (strcmp(argv[3], "--probe-resp") == 0) { + mode = MODE_PROBE_RESPONSE; + } else if (strcmp(argv[3], "--probe-req") == 0) { + mode = MODE_PROBE_REQUEST; + } else if (strcmp(argv[3], "--deauth") == 0) { + mode = MODE_DEAUTH; + } else if (strcmp(argv[3], "--disassoc") == 0) { + mode = MODE_DISASSOC; + } else if (strcmp(argv[3], "--assoc-resp") == 0) { + mode = MODE_ASSOC_RESPONSE; + } else if (strcmp(argv[3], "--assoc-req") == 0) { + mode = MODE_ASSOC_REQUEST; + } else if (strcmp(argv[3], "--reassoc-resp") == 0) { + mode = MODE_REASSOC_RESPONSE; + } else if (strcmp(argv[3], "--reassoc-req") == 0) { + mode = MODE_REASSOC_REQUEST; + } else if (strcmp(argv[3], "--auth") == 0) { + mode = MODE_AUTH; + } else if (strcmp(argv[3], "--timing-ad") == 0) { + mode = MODE_TIMING_AD; + } else if (strcmp(argv[3], "--action") == 0) { + mode = MODE_ACTION; + } else if (strcmp(argv[3], "--action-noack") == 0) { + mode = MODE_ACTION_NOACK; + } else if (strcmp(argv[3], "--atim") == 0) { + mode = MODE_ATIM; + } else if (strcmp(argv[3], "--rts") == 0) { + mode = MODE_RTS; + } else if (strcmp(argv[3], "--cts") == 0) { + mode = MODE_CTS; + } else { + help(argv[0]); + exit(EXIT_SUCCESS); + } +} + +int main(int argc, const char *argv[]) { + signal(SIGINT, handle_interupt); + handle_args(argc, argv); + + printf("Starting in 5 seconds...\n"); + + sleep(5); + + switch (mode) { + case MODE_BEACON: + inject_beacons(0); + break; + case MODE_RANDOM_BEACON: + inject_beacons(1); + break; + case MODE_PROBE_RESPONSE: + inject_probe_responses(); + break; + case MODE_PROBE_REQUEST: + inject_probe_requests(); + break; + case MODE_DEAUTH: + inject_deauths(); + break; + case MODE_DISASSOC: + inject_disassocs(); + break; + case MODE_ASSOC_REQUEST: + inject_assoc_requests(); + break; + case MODE_ASSOC_RESPONSE: + inject_assoc_responses(); + break; + case MODE_REASSOC_REQUEST: + inject_reassoc_requests(); + break; + case MODE_REASSOC_RESPONSE: + inject_reassoc_responses(); + break; + case MODE_AUTH: + inject_auths(); + break; + case MODE_ACTION: + inject_actions(); + break; + case MODE_ACTION_NOACK: + inject_action_noacks(); + break; + case MODE_TIMING_AD: + inject_timing_ads(); + break; + case MODE_ATIM: + inject_atim(); + break; + case MODE_RTS: + inject_rts(); + break; + case MODE_CTS: + inject_cts(); + break; + } + + return 0; +} diff --git a/test/src/test_misc.c b/test/src/test_misc.c new file mode 100644 index 0000000..f103455 --- /dev/null +++ b/test/src/test_misc.c @@ -0,0 +1,30 @@ +#include +#include +#include + +void gen_macs() { + printf("Getting 10 random MAC addresses:\n"); + for(int i = 0; i < 10; i++) { + unsigned char mac[6] = {0}; + libwifi_random_mac(mac, NULL); + printf(MACSTR "\n", MAC2STR(mac)); + } + + printf("Generating 10 random MAC addresses with 00:20:91 OUI:\n"); + for(int i = 0; i < 10; i++) { + unsigned char mac[6] = {0}; + libwifi_random_mac(mac, (unsigned char *) "\x00\x20\x91"); + printf(MACSTR "\n", MAC2STR(mac)); + } + printf("\n"); +} + +int main() { + libwifi_dummy(); + + printf("libwifi version: %s\n\n", libwifi_get_version()); + + gen_macs(); + + return 0; +} diff --git a/test/src/test_parsing.c b/test/src/test_parsing.c new file mode 100644 index 0000000..c345346 --- /dev/null +++ b/test/src/test_parsing.c @@ -0,0 +1,613 @@ +#include "helpers.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PCAP_SAVEFILE "/tmp/debug.pcap" +#define FILTER "" +#define MODE_BEACON 1 +#define MODE_PROBE_RESPONSE 2 +#define MODE_PROBE_REQUEST 3 +#define MODE_EAPOL 4 +#define MODE_DEAUTH 5 +#define MODE_DISASSOC 6 +#define MODE_ASSOC_RESPONSE 7 +#define MODE_ASSOC_REQUEST 8 +#define MODE_REASSOC_REQUEST 9 +#define MODE_REASSOC_RESPONSE 10 +#define MODE_DATA 11 +#define MODE_ALL 99 + +static pcap_t *handle; +pcap_dumper_t *pd; +static struct bpf_program *filter; +static int got_radiotap; +static unsigned long packet_num = 0; +static int mode = 0; +static int parse_radiotap_header = 0; + +struct libwifi_bss bss = {0}; +struct libwifi_sta sta = {0}; + +void help(const char *); +void parse_packet(unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet); +void print_bss_info(struct libwifi_bss *bss); +void print_sta_info(struct libwifi_sta *sta); +void print_tag_info(unsigned char *data, size_t data_len); + +void interrupted(int signum) { + pcap_dump_close(pd); + pcap_close(handle); +} + +void print_bss_info(struct libwifi_bss *bss) { + if (bss == NULL) { + return; + } + + printf("=== BSS Parsing ===\n"); + printf("ESSID: %s\n", bss->hidden ? "(hidden)" : bss->ssid); + printf("BSSID: " MACSTR "\n", MAC2STR(bss->bssid)); + printf("Receiver: " MACSTR "\n", MAC2STR(bss->receiver)); + printf("Transmitter: " MACSTR "\n", MAC2STR(bss->transmitter)); + printf("Channel: %d\n", bss->channel); + printf("WPS: %s\n", bss->wps ? "yes" : "no"); + + char sec_buf[LIBWIFI_SECURITY_BUF_LEN]; + libwifi_get_security_type(bss, sec_buf); + printf("Encryption: %s\n", sec_buf); + + libwifi_get_group_ciphers(bss, sec_buf); + printf("\tGroup Ciphers: %s\n", sec_buf); + + libwifi_get_pairwise_ciphers(bss, sec_buf); + printf("\tPairwise Ciphers: %s\n", sec_buf); + + libwifi_get_auth_key_suites(bss, sec_buf); + printf("\tAuth Key Suites: %s\n", sec_buf); + + if (bss->rsn_info.rsn_capabilities & LIBWIFI_RSN_CAPAB_MFP_CAPABLE) { + printf("\tMFP Capable: Yes\n"); + } + if (bss->rsn_info.rsn_capabilities & LIBWIFI_RSN_CAPAB_MFP_REQUIRED) { + printf("\tMFP Required: Yes\n"); + } + + if (bss->tags.length) { + printf("Tagged Parameters:\n"); + print_tag_info(bss->tags.parameters, bss->tags.length); + } else { + printf("Tagged Parameters: None\n"); + } + + printf("=== BSS End ===\n"); + printf("\n\n"); +} + +void print_sta_info(struct libwifi_sta *sta) { + if (sta == NULL) { + return; + } + + printf("=== STA Parsing ===\n"); + + if (sta->broadcast_ssid) { + printf("ESSID: \n"); + } else { + printf("ESSID: %s\n", sta->ssid); + } + printf("Channel: %u\n", sta->channel); + printf("BSSID: " MACSTR "\n", MAC2STR(sta->bssid)); + printf("MAC: " MACSTR "\n", MAC2STR(sta->transmitter)); + + printf("=== STA End ===\n"); + printf("\n\n"); +} + +void print_tag_info(unsigned char *data, size_t data_len) { + struct libwifi_tag_iterator it; + if (libwifi_tag_iterator_init(&it, data, data_len) != 0) { + printf("Couldn't initialise tag iterator\n"); + return; + } + do { + printf("\tTag: %d (Size: %d)\n", it.tag_header->tag_num, it.tag_header->tag_len); + + int max_size = 16; + if (it.tag_header->tag_len < 16) { + max_size = it.tag_header->tag_len; + } + printf("\t%d bytes of Tag Data: ", max_size); + for (size_t i = 0; i < max_size; i++) { + printf("%02x ", it.tag_data[i]); + } + printf("\n"); + } while (libwifi_tag_iterator_next(&it) != -1); +} + +void parse_radiotap(const unsigned char *packet) { + struct libwifi_radiotap_info rtap_info; + libwifi_parse_radiotap_info(&rtap_info, packet); + + printf("=== Radiotap Parsing ===\n"); + printf("Radiotap Channel: %d\n", rtap_info.channel.freq); + printf("Radiotap Channel Flags: 0x%04x\n", rtap_info.channel.flags); + printf("Radiotap Rate: %.2f Mb/s\n", rtap_info.rate); + printf("Radiotap Rate Raw: 0x%02x\n", rtap_info.rate_raw); + printf("Radiotap Signal: %d dBm\n", rtap_info.signal); + for (int i = 0; i < rtap_info.antenna_count; i++) { + printf("Radiotap Antenna %d: %d dBm\n", rtap_info.antennas[i].antenna_number, rtap_info.antennas[i].signal); + } + printf("Radiotap Flags: 0x%04x\n", rtap_info.flags); + printf("Radiotap Extended Flags: 0x%08x\n", rtap_info.extended_flags); + printf("Radiotap RX Flags: 0x%04x\n", rtap_info.rx_flags); + printf("Radiotap TX Flags: 0x%04x\n", rtap_info.tx_flags); + printf("Radiotap TX Power: %d\n", rtap_info.tx_power); + printf("Radiotap RTS Retries: %d\n", rtap_info.rts_retries); + printf("Radiotap Data Retries: %d\n", rtap_info.data_retries); + printf("=== Radiotap End ===\n"); +} + +void parse_beacon(struct libwifi_frame frame, unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet) { + if (frame.frame_control.type == TYPE_MANAGEMENT && frame.frame_control.subtype == SUBTYPE_BEACON) { + printf("Packet : %lu\n", packet_num); + int ret = libwifi_parse_beacon(&bss, &frame); + if (ret != 0) { + printf("Failed to parse beacon: %d\n", ret); + pcap_dump(args, header, packet); + return; + } + + if (got_radiotap && parse_radiotap_header) { + parse_radiotap(packet); + } + + print_bss_info(&bss); + } +} + +void parse_probe_request(struct libwifi_frame frame, unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet) { + if (frame.frame_control.type == TYPE_MANAGEMENT && frame.frame_control.subtype == SUBTYPE_PROBE_REQ) { + printf("Packet : %lu\n", packet_num); + int ret = libwifi_parse_probe_req(&sta, &frame); + if (ret != 0) { + printf("Failed to parse probe request: %d\n", ret); + pcap_dump(args, header, packet); + return; + } + + if (got_radiotap && parse_radiotap_header) { + parse_radiotap(packet); + } + + print_sta_info(&sta); + } +} +void parse_probe_response(struct libwifi_frame frame, unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet) { + if (frame.frame_control.type == TYPE_MANAGEMENT && frame.frame_control.subtype == SUBTYPE_PROBE_RESP) { + printf("Packet : %lu\n", packet_num); + int ret = libwifi_parse_probe_resp(&bss, &frame); + if (ret != 0) { + printf("Failed to parse probe response: %d\n", ret); + pcap_dump(args, header, packet); + return; + } + + if (got_radiotap && parse_radiotap_header) { + parse_radiotap(packet); + } + + print_bss_info(&bss); + } +} +void parse_deauth(struct libwifi_frame frame, unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet) { + if (frame.frame_control.type == TYPE_MANAGEMENT && frame.frame_control.subtype == SUBTYPE_DEAUTH) { + printf("Packet : %lu\n", packet_num); + struct libwifi_parsed_deauth deauth; + int ret = libwifi_parse_deauth(&deauth, &frame); + if (ret != 0) { + printf("Failed to parse deauthentication: %d\n", ret); + pcap_dump(args, header, packet); + return; + } + + if (got_radiotap && parse_radiotap_header) { + parse_radiotap(packet); + } + + printf("=== Deauthentication Frame ===\n"); + if (deauth.ordered) { + printf("Address 1: " MACSTR "\n", MAC2STR(deauth.frame_header.ordered.addr1)); + printf("Address 2: " MACSTR "\n", MAC2STR(deauth.frame_header.ordered.addr2)); + printf("Address 3: " MACSTR "\n", MAC2STR(deauth.frame_header.ordered.addr3)); + } else { + printf("Address 1: " MACSTR "\n", MAC2STR(deauth.frame_header.unordered.addr1)); + printf("Address 2: " MACSTR "\n", MAC2STR(deauth.frame_header.unordered.addr2)); + printf("Address 3: " MACSTR "\n", MAC2STR(deauth.frame_header.unordered.addr3)); + } + + printf("Reason: %d (0x%04x)\n", deauth.fixed_parameters.reason_code, deauth.fixed_parameters.reason_code); + + if (deauth.tags.length) { + printf("Tagged Parameters:\n"); + print_tag_info(deauth.tags.parameters, deauth.tags.length); + } else { + printf("Tagged Parameters: None\n"); + } + + printf("=== End Deauthentication Frame ===\n"); + printf("\n\n"); + } +} +void parse_disassoc(struct libwifi_frame frame, unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet) { + if (frame.frame_control.type == TYPE_MANAGEMENT && frame.frame_control.subtype == SUBTYPE_DISASSOC) { + printf("Packet : %lu\n", packet_num); + struct libwifi_parsed_disassoc disassoc; + int ret = libwifi_parse_disassoc(&disassoc, &frame); + if (ret != 0) { + printf("Failed to parse diassociation: %d\n", ret); + pcap_dump(args, header, packet); + return; + } + + if (got_radiotap && parse_radiotap_header) { + parse_radiotap(packet); + } + + printf("=== Disassociation Frame ===\n"); + if (disassoc.ordered) { + printf("Address 1: " MACSTR "\n", MAC2STR(disassoc.frame_header.ordered.addr1)); + printf("Address 2: " MACSTR "\n", MAC2STR(disassoc.frame_header.ordered.addr2)); + printf("Address 3: " MACSTR "\n", MAC2STR(disassoc.frame_header.ordered.addr3)); + } else { + printf("Address 1: " MACSTR "\n", MAC2STR(disassoc.frame_header.unordered.addr1)); + printf("Address 2: " MACSTR "\n", MAC2STR(disassoc.frame_header.unordered.addr2)); + printf("Address 3: " MACSTR "\n", MAC2STR(disassoc.frame_header.unordered.addr3)); + } + + printf("Reason: %d (0x%04x)\n", disassoc.fixed_parameters.reason_code, disassoc.fixed_parameters.reason_code); + + printf("Tagged Parameters:\n"); + if (disassoc.tags.length == 0) { + printf("\tNo Tags\n"); + } else { + printf("\tTags Found\n"); + } + + printf("=== End Disassociation Frame ===\n"); + printf("\n\n"); + } +} +void parse_assoc_request(struct libwifi_frame frame, unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet) { + if (frame.frame_control.type == TYPE_MANAGEMENT && frame.frame_control.subtype == SUBTYPE_ASSOC_REQ) { + printf("Packet : %lu\n", packet_num); + int ret = libwifi_parse_assoc_req(&sta, &frame); + if (ret != 0) { + printf("Failed to parse association request: %d\n", ret); + pcap_dump(args, header, packet); + return; + } + + if (got_radiotap && parse_radiotap_header) { + parse_radiotap(packet); + } + + print_sta_info(&sta); + } +} +void parse_assoc_response(struct libwifi_frame frame, unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet) { + if (frame.frame_control.type == TYPE_MANAGEMENT && frame.frame_control.subtype == SUBTYPE_ASSOC_RESP) { + printf("Packet : %lu\n", packet_num); + int ret = libwifi_parse_assoc_resp(&bss, &frame); + if (ret != 0) { + printf("Failed to parse association response: %d\n", ret); + pcap_dump(args, header, packet); + return; + } + + if (got_radiotap && parse_radiotap_header) { + parse_radiotap(packet); + } + + print_bss_info(&bss); + } +} +void parse_reassoc_request(struct libwifi_frame frame, unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet) { + if (frame.frame_control.type == TYPE_MANAGEMENT && frame.frame_control.subtype == SUBTYPE_REASSOC_REQ) { + printf("Packet : %lu\n", packet_num); + int ret = libwifi_parse_reassoc_req(&sta, &frame); + if (ret != 0) { + printf("Failed to parse reassociation request: %d\n", ret); + pcap_dump(args, header, packet); + return; + } + + if (got_radiotap && parse_radiotap_header) { + parse_radiotap(packet); + } + + print_sta_info(&sta); + } +} +void parse_reassoc_response(struct libwifi_frame frame, unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet) { + if (frame.frame_control.type == TYPE_MANAGEMENT && frame.frame_control.subtype == SUBTYPE_REASSOC_RESP) { + printf("Packet : %lu\n", packet_num); + int ret = libwifi_parse_reassoc_resp(&bss, &frame); + if (ret != 0) { + printf("Failed to parse reassociation response: %d\n", ret); + pcap_dump(args, header, packet); + return; + } + + if (got_radiotap && parse_radiotap_header) { + parse_radiotap(packet); + } + + print_bss_info(&bss); + } +} +void parse_data_eapol(struct libwifi_frame frame, unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet) { + if (frame.frame_control.type == TYPE_DATA) { + if (libwifi_check_wpa_handshake(&frame) > 0) { + printf("=== EAPOL ===\n"); + printf("WPA Handshake\n"); + int part = libwifi_check_wpa_message(&frame); + printf("WPA Handshake Message: %s\n", libwifi_get_wpa_message_string(&frame)); + + struct libwifi_wpa_auth_data data = {0}; + libwifi_get_wpa_data(&frame, &data); + + printf("EAPOL: Version: %d\n", data.version); + printf("EAPOL: Type: %d\n", data.type); + printf("EAPOL: Length: %d\n", data.length); + printf("EAPOL: Descriptor: %d\n", data.descriptor); + printf("EAPOL: Key Info: Information: 0x%04x\n", data.key_info.information); + printf("EAPOL: Key Info: Key Length: %d\n", data.key_info.key_length); + printf("EAPOL: Key Info: Replay Counter: %lu\n", data.key_info.replay_counter); + printf("EAPOL: Key Info: Nonce: "); + for (size_t i = 0; i < sizeof(data.key_info.nonce); ++i) printf("%02x ", data.key_info.nonce[i]); + printf("\n"); + printf("EAPOL: Key Info: IV: "); + for (size_t i = 0; i < sizeof(data.key_info.iv); ++i) printf("%02x ", data.key_info.iv[i]); + printf("\n"); + printf("EAPOL: Key Info: RSC: "); + for (size_t i = 0; i < sizeof(data.key_info.rsc); ++i) printf("%02x ", data.key_info.rsc[i]); + printf("\n"); + printf("EAPOL: Key Info: ID: "); + for (size_t i = 0; i < sizeof(data.key_info.id); ++i) printf("%02x ", data.key_info.id[i]); + printf("\n"); + printf("EAPOL: Key Info: MIC: "); + for (size_t i = 0; i < sizeof(data.key_info.mic); ++i) printf("%02x ", data.key_info.mic[i]); + printf("\n"); + printf("EAPOL: Key Info: Key Data Length: %d\n", data.key_info.key_data_length); + if (data.key_info.key_data_length) { + printf("EAPOL: Key Info: Key Data: "); + for (size_t i = 0; i < data.key_info.key_data_length; ++i) printf("%02x ", data.key_info.key_data[i]); + printf("\n"); + } + + libwifi_free_wpa_data(&data); + + printf("\n\n"); + } + } +} + +void parse_data(struct libwifi_frame frame, unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet) { + if (frame.frame_control.type == TYPE_DATA) { + if (frame.flags & LIBWIFI_FLAGS_IS_QOS) { + printf("Receiver: " MACSTR "\n", MAC2STR(frame.header.data_qos.addr1)); + printf("Transmitter: " MACSTR "\n", MAC2STR(frame.header.data_qos.addr2)); + } else { + printf("Receiver: " MACSTR "\n", MAC2STR(frame.header.data.addr1)); + printf("Transmitter: " MACSTR "\n", MAC2STR(frame.header.data.addr2)); + } + printf("Body Length: %zu\n", frame.len - frame.header_len); + printf("Body:\n"); + hexdump(frame.body, frame.len - frame.header_len); + } +} + +void parse_packet(unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet) { + ++packet_num; + unsigned long data_len = header->caplen; + unsigned char *data = (unsigned char *) packet; + + struct libwifi_frame frame = {0}; + int ret = libwifi_get_wifi_frame(&frame, data, data_len, 1); + if (ret != 0) { + printf("[!] Error getting libwifi_frame: %d\n", ret); + return; + } + + memset(&bss, 0, sizeof(struct libwifi_bss)); + memset(&sta, 0, sizeof(struct libwifi_sta)); + + switch (mode) { + case MODE_BEACON: + parse_beacon(frame, args, header, packet); + break; + case MODE_PROBE_REQUEST: + parse_probe_request(frame, args, header, packet); + break; + case MODE_PROBE_RESPONSE: + parse_probe_response(frame, args, header, packet); + break; + case MODE_DEAUTH: + parse_deauth(frame, args, header, packet); + break; + case MODE_DISASSOC: + parse_disassoc(frame, args, header, packet); + break; + case MODE_ASSOC_REQUEST: + parse_assoc_request(frame, args, header, packet); + break; + case MODE_ASSOC_RESPONSE: + parse_assoc_response(frame, args, header, packet); + break; + case MODE_REASSOC_REQUEST: + parse_reassoc_request(frame, args, header, packet); + break; + case MODE_REASSOC_RESPONSE: + parse_reassoc_response(frame, args, header, packet); + break; + case MODE_EAPOL: + parse_data_eapol(frame, args, header, packet); + break; + case MODE_DATA: + parse_data(frame, args, header, packet); + break; + case MODE_ALL: + parse_beacon(frame, args, header, packet); + parse_probe_request(frame, args, header, packet); + parse_probe_response(frame, args, header, packet); + parse_deauth(frame, args, header, packet); + parse_disassoc(frame, args, header, packet); + parse_assoc_request(frame, args, header, packet); + parse_assoc_response(frame, args, header, packet); + parse_reassoc_request(frame, args, header, packet); + parse_reassoc_response(frame, args, header, packet); + parse_data_eapol(frame, args, header, packet); + parse_data(frame, args, header, packet); + default: + break; + } + + libwifi_free_bss(&bss); + libwifi_free_wifi_frame(&frame); +} + +void help(const char *name) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\t%s --interface [interface] [--mode] [--radiotap]\n", name); + fprintf(stderr, "\t\tor\n"); + fprintf(stderr, "\t%s --file [capture file] [--mode] [--radiotap]\n", name); + fprintf(stderr, "\n"); + fprintf(stderr, "Modes:\n"); + fprintf(stderr, "\t--beacon\n"); + fprintf(stderr, "\t--probe-req\n"); + fprintf(stderr, "\t--probe-resp\n"); + fprintf(stderr, "\t--deauth\n"); + fprintf(stderr, "\t--disassoc\n"); + fprintf(stderr, "\t--assoc-req\n"); + fprintf(stderr, "\t--assoc-resp\n"); + fprintf(stderr, "\t--reassoc-req\n"); + fprintf(stderr, "\t--reassoc-resp\n"); + fprintf(stderr, "\t--eapol\n"); +} + +void handle_args(int argc, const char *argv[]) { + char errbuf[PCAP_ERRBUF_SIZE]; + + if (argc < 4) { + help(argv[0]); + exit(EXIT_SUCCESS); + } + + if (strcmp(argv[1], "--file") == 0) { + if ((handle = pcap_open_offline(argv[2], errbuf)) == NULL) { + fprintf(stderr, "Couldn't read file %s: %s\n", argv[2], errbuf); + exit(EXIT_FAILURE); + } + } else if (strcmp(argv[1], "--interface") == 0) { + if ((handle = pcap_create(argv[2], errbuf)) == NULL) { + fprintf(stderr, "Failed to open interface \"%s\" for sniffing: %s\n", argv[2], errbuf); + exit(EXIT_FAILURE); + } + if (pcap_activate(handle) == 0) { + printf("[+] Started sniffing on %s\n", argv[2]); + } else { + fprintf(stderr, "[!] Couldn't activate capture: %s.\n", pcap_geterr(handle)); + pcap_close(handle); + exit(EXIT_FAILURE); + } + } else { + help(argv[0]); + exit(EXIT_SUCCESS); + } + + if (strcmp(argv[3], "--beacon") == 0) { + mode = MODE_BEACON; + } else if (strcmp(argv[3], "--probe-req") == 0) { + mode = MODE_PROBE_REQUEST; + } else if (strcmp(argv[3], "--probe-resp") == 0) { + mode = MODE_PROBE_RESPONSE; + } else if (strcmp(argv[3], "--deauth") == 0) { + mode = MODE_DEAUTH; + } else if (strcmp(argv[3], "--disassoc") == 0) { + mode = MODE_DISASSOC; + } else if (strcmp(argv[3], "--assoc-req") == 0) { + mode = MODE_ASSOC_REQUEST; + } else if (strcmp(argv[3], "--assoc-resp") == 0) { + mode = MODE_ASSOC_RESPONSE; + } else if (strcmp(argv[3], "--reassoc-req") == 0) { + mode = MODE_REASSOC_REQUEST; + } else if (strcmp(argv[3], "--reassoc-resp") == 0) { + mode = MODE_REASSOC_RESPONSE; + } else if (strcmp(argv[3], "--eapol") == 0) { + mode = MODE_EAPOL; + } else if (strcmp(argv[3], "--data") == 0) { + mode = MODE_DATA; + } else if (strcmp(argv[3], "--all") == 0) { + mode = MODE_ALL; + } else { + help(argv[0]); + exit(EXIT_SUCCESS); + } + + if (argc > 4) { + if (strcmp(argv[4], "--radiotap") == 0) { + parse_radiotap_header = 1; + } + } +} + +int main(int argc, const char *argv[]) { + packet_num = 0; + char errbuf[PCAP_ERRBUF_SIZE]; + + handle_args(argc, argv); + + int linktype = pcap_datalink(handle); + if (linktype == DLT_IEEE802_11_RADIO) { + got_radiotap = 1; + } else if (linktype == DLT_IEEE802_11) { + got_radiotap = 0; + } else { + fprintf(stderr, "[!] 802.11 and radiotap headers not provided (%d)\n", pcap_datalink(handle)); + pcap_close(handle); + exit(EXIT_FAILURE); + } + + if ((filter = malloc(sizeof(struct bpf_program))) == NULL) { + perror("Malloc failure"); + pcap_close(handle); + exit(EXIT_FAILURE); + } + printf("[*] Compiling and optimizing frame filter, this can take a second\n"); + if (pcap_compile(handle, filter, FILTER, 0, 0) != 0) { + fprintf(stderr, "[!] Couldn't compile filter: %s\n", pcap_geterr(handle)); + pcap_close(handle); + free(filter); + exit(EXIT_FAILURE); + } + if (pcap_setfilter(handle, filter) != 0) { + fprintf(stderr, "[!] Couldn't set filter: %s\n", pcap_geterr(handle)); + pcap_close(handle); + free(filter); + exit(EXIT_FAILURE); + } + printf("[+] Complete\n"); + + pd = pcap_dump_open(handle, PCAP_SAVEFILE); + pcap_loop(handle, -1 /*INFINITY*/, &parse_packet, (unsigned char *) pd); + + return 0; +} -- cgit 1.4.1