From 74552bd857f15bc70fd2e2d876237b7d9900324e Mon Sep 17 00:00:00 2001 From: Matthias Schulz Date: Mon, 12 Mar 2018 23:55:57 +0100 Subject: [PATCH] initial commit of our channel state information extractor --- LICENSE | 61 +++++++++ Makefile | 219 +++++++++++++++++++++++++++++ README.md | 96 +++++++++++++ include/macros.inc | 43 ++++++ include/rxhdrlen.h | 38 ++++++ patch.ld | 10 ++ src/csi_extraction.c | 234 +++++++++++++++++++++++++++++++ src/ioctl.c | 125 +++++++++++++++++ src/patch.c | 61 +++++++++ src/regulations.c | 117 ++++++++++++++++ src/rxhdrlen.c | 67 +++++++++ src/ucode.patch | 318 +++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 1389 insertions(+) create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100644 include/macros.inc create mode 100644 include/rxhdrlen.h create mode 100644 patch.ld create mode 100644 src/csi_extraction.c create mode 100644 src/ioctl.c create mode 100644 src/patch.c create mode 100644 src/regulations.c create mode 100644 src/rxhdrlen.c create mode 100644 src/ucode.patch diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6ab6209 --- /dev/null +++ b/LICENSE @@ -0,0 +1,61 @@ + + ########### ########### ########## ########## + ############ ############ ############ ############ + ## ## ## ## ## ## ## + ## ## ## ## ## ## ## + ########### #### ###### ## ## ## ## ###### + ########### #### # ## ## ## ## # # + ## ## ###### ## ## ## ## # # + ## ## # ## ## ## ## # # + ############ ##### ###### ## ## ## ##### ###### + ########### ########### ## ## ## ########## + + S E C U R E M O B I L E N E T W O R K I N G + +License: + +Copyright (c) 2018 Matthias Schulz, Jakob Link, Francesco Gringoli + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +1. The above copyright notice and this permission notice shall be + include in all copies or substantial portions of the Software. + +2. Any use of the Software which results in an academic publication or + other publication which includes a bibliography must include + citations to the nexmon project a) and the paper cited under b) or + the thesis cited under c): + + a) "Matthias Schulz, Daniel Wegemer and Matthias Hollick. Nexmon: + The C-based Firmware Patching Framework. https://nexmon.org" + + b) "Matthias Schulz, Jakob Link, Francesco Gringoli, and Matthias + Hollick. Shadow Wi-Fi: Teaching Smart- phones to Transmit Raw + Signals and to Extract Channel State Information to Implement + Practical Covert Channels over Wi-Fi. Accepted to appear in + Proceedings of the 16th ACM International Conference on Mobile + Systems, Applications, and Services (MobiSys 2018), June 2018." + + c) "Matthias Schulz. Teaching Your Wireless Card New Tricks: + Smartphone Performance and Security Enhancements through Wi-Fi + Firmware Modifications. Dr.-Ing. thesis, Technische Universität + Darmstadt, Germany, February 2018." + +3. The Software is not used by, in cooperation with, or on behalf of + any armed forces, intelligence agencies, reconnaissance agencies, + defense agencies, offense agencies or any supplier, contractor, or + research associated. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b5ae394 --- /dev/null +++ b/Makefile @@ -0,0 +1,219 @@ +GIT_VERSION := $(shell git describe --abbrev=4 --dirty --always --tags) +include ../version.mk +include $(FW_PATH)/definitions.mk + +LOCAL_SRCS=$(wildcard src/*.c) src/ucode_compressed.c src/templateram.c +COMMON_SRCS=$(wildcard $(NEXMON_ROOT)/patches/common/*.c) +FW_SRCS=$(wildcard $(FW_PATH)/*.c) + +ifdef UCODEFILE +ifeq ($(wildcard src/$(UCODEFILE)), ) +$(error selected src/$(UCODEFILE) does not exist) +endif +endif + +ADBSERIAL := +ADBFLAGS := $(ADBSERIAL) + +UCODEFILE=ucode.asm + +OBJS=$(addprefix obj/,$(notdir $(LOCAL_SRCS:.c=.o)) $(notdir $(COMMON_SRCS:.c=.o)) $(notdir $(FW_SRCS:.c=.o))) + +CFLAGS= \ + -fplugin=$(CCPLUGIN) \ + -fplugin-arg-nexmon-objfile=$@ \ + -fplugin-arg-nexmon-prefile=gen/nexmon.pre \ + -fplugin-arg-nexmon-chipver=$(NEXMON_CHIP_NUM) \ + -fplugin-arg-nexmon-fwver=$(NEXMON_FW_VERSION_NUM) \ + -fno-strict-aliasing \ + -DNEXMON_CHIP=$(NEXMON_CHIP) \ + -DNEXMON_FW_VERSION=$(NEXMON_FW_VERSION) \ + -DPATCHSTART=$(PATCHSTART) \ + -DUCODESIZE=$(UCODESIZE) \ + -DGIT_VERSION=\"$(GIT_VERSION)\" \ + -DBUILD_NUMBER=\"$$(cat BUILD_NUMBER)\" \ + -Wall -Werror -Wno-unused-function -Wno-unused-variable \ + -O2 -nostdlib -nostartfiles -ffreestanding -mthumb -march=$(NEXMON_ARCH) \ + -ffunction-sections -fdata-sections \ + -I$(NEXMON_ROOT)/patches/include \ + -Iinclude \ + -I$(FW_PATH) + +all: fw_bcmdhd.bin + +init: FORCE + $(Q)if ! test -f BUILD_NUMBER; then echo 0 > BUILD_NUMBER; fi + $(Q)echo $$(($$(cat BUILD_NUMBER) + 1)) > BUILD_NUMBER + $(Q)touch src/version.c + $(Q)make -s -f $(NEXMON_ROOT)/patches/common/header.mk + $(Q)mkdir -p obj gen log + +obj/%.o: src/%.c + @printf "\033[0;31m COMPILING\033[0m %s => %s (details: log/compiler.log)\n" $< $@ + $(Q)cat gen/nexmon.pre 2>>log/error.log | gawk '{ if ($$3 != "$@") print; }' > tmp && mv tmp gen/nexmon.pre + $(Q)$(CC)gcc $(CFLAGS) -c $< -o $@ >>log/compiler.log + +obj/%.o: $(NEXMON_ROOT)/patches/common/%.c + @printf "\033[0;31m COMPILING\033[0m %s => %s (details: log/compiler.log)\n" $< $@ + $(Q)cat gen/nexmon.pre 2>>log/error.log | gawk '{ if ($$3 != "$@") print; }' > tmp && mv tmp gen/nexmon.pre + $(Q)$(CC)gcc $(CFLAGS) -c $< -o $@ >>log/compiler.log + +obj/%.o: $(FW_PATH)/%.c + @printf "\033[0;31m COMPILING\033[0m %s => %s (details: log/compiler.log)\n" $< $@ + $(Q)cat gen/nexmon.pre 2>>log/error.log | gawk '{ if ($$3 != "$@") print; }' > tmp && mv tmp gen/nexmon.pre + $(Q)$(CC)gcc $(CFLAGS) -c $< -o $@ >>log/compiler.log + +gen/nexmon2.pre: $(OBJS) + @printf "\033[0;31m PREPARING\033[0m %s => %s\n" "gen/nexmon.pre" $@ + $(Q)cat gen/nexmon.pre | awk '{ if ($$3 != "obj/flashpatches.o" && $$3 != "obj/wrapper.o") { print $$0; } }' > tmp + $(Q)cat gen/nexmon.pre | awk '{ if ($$3 == "obj/flashpatches.o" || $$3 == "obj/wrapper.o") { print $$0; } }' >> tmp + $(Q)cat tmp | awk '{ if ($$1 ~ /^0x/) { if ($$3 != "obj/flashpatches.o" && $$3 != "obj/wrapper.o") { if (!x[$$1]++) { print $$0; } } else { if (!x[$$1]) { print $$0; } } } else { print $$0; } }' > gen/nexmon2.pre + +gen/nexmon.ld: gen/nexmon2.pre $(OBJS) + @printf "\033[0;31m GENERATING LINKER FILE\033[0m gen/nexmon.pre => %s\n" $@ + $(Q)sort gen/nexmon2.pre | gawk -f $(NEXMON_ROOT)/buildtools/scripts/nexmon.ld.awk > $@ + +gen/nexmon.mk: gen/nexmon2.pre $(OBJS) $(FW_PATH)/definitions.mk + @printf "\033[0;31m GENERATING MAKE FILE\033[0m gen/nexmon.pre => %s\n" $@ + $(Q)printf "fw_bcmdhd.bin: gen/patch.elf FORCE\n" > $@ + $(Q)sort gen/nexmon2.pre | \ + gawk -v src_file=gen/patch.elf -f $(NEXMON_ROOT)/buildtools/scripts/nexmon.mk.1.awk | \ + gawk -v ramstart=$(RAMSTART) -f $(NEXMON_ROOT)/buildtools/scripts/nexmon.mk.2.awk >> $@ + $(Q)printf "\nFORCE:\n" >> $@ + $(Q)gawk '!a[$$0]++' $@ > tmp && mv tmp $@ + +gen/flashpatches.ld: gen/nexmon2.pre $(OBJS) + @printf "\033[0;31m GENERATING LINKER FILE\033[0m gen/nexmon.pre => %s\n" $@ + $(Q)sort gen/nexmon2.pre | \ + gawk -f $(NEXMON_ROOT)/buildtools/scripts/flashpatches.ld.awk > $@ + +gen/flashpatches.mk: gen/nexmon2.pre $(OBJS) $(FW_PATH)/definitions.mk + @printf "\033[0;31m GENERATING MAKE FILE\033[0m gen/nexmon.pre => %s\n" $@ + $(Q)cat gen/nexmon2.pre | gawk \ + -v fp_data_base=$(FP_DATA_BASE) \ + -v fp_config_base=$(FP_CONFIG_BASE) \ + -v fp_data_end_ptr=$(FP_DATA_END_PTR) \ + -v fp_config_base_ptr_1=$(FP_CONFIG_BASE_PTR_1) \ + -v fp_config_end_ptr_1=$(FP_CONFIG_END_PTR_1) \ + -v fp_config_base_ptr_2=$(FP_CONFIG_BASE_PTR_2) \ + -v fp_config_end_ptr_2=$(FP_CONFIG_END_PTR_2) \ + -v ramstart=$(RAMSTART) \ + -v out_file=fw_bcmdhd.bin \ + -v src_file=gen/patch.elf \ + -f $(NEXMON_ROOT)/buildtools/scripts/flashpatches.mk.awk > $@ + +gen/memory.ld: $(FW_PATH)/definitions.mk + @printf "\033[0;31m GENERATING LINKER FILE\033[0m %s\n" $@ + $(Q)printf "rom : ORIGIN = 0x%08x, LENGTH = 0x%08x\n" $(ROMSTART) $(ROMSIZE) > $@ + $(Q)printf "ram : ORIGIN = 0x%08x, LENGTH = 0x%08x\n" $(RAMSTART) $(RAMSIZE) >> $@ + $(Q)printf "patch : ORIGIN = 0x%08x, LENGTH = 0x%08x\n" $(PATCHSTART) $(PATCHSIZE) >> $@ + $(Q)printf "ucode : ORIGIN = 0x%08x, LENGTH = 0x%08x\n" $(UCODESTART) $$(($(FP_CONFIG_BASE) - $(UCODESTART))) >> $@ + $(Q)printf "fpconfig : ORIGIN = 0x%08x, LENGTH = 0x%08x\n" $(FP_CONFIG_BASE) $(FP_CONFIG_SIZE) >> $@ + +gen/patch.elf: patch.ld gen/nexmon.ld gen/flashpatches.ld gen/memory.ld $(OBJS) + @printf "\033[0;31m LINKING OBJECTS\033[0m => %s (details: log/linker.log, log/linker.err)\n" $@ + $(Q)$(CC)ld -T $< -o $@ --gc-sections --print-gc-sections -M >>log/linker.log 2>>log/linker.err + +fw_bcmdhd.bin: init gen/patch.elf $(FW_PATH)/$(RAM_FILE) gen/nexmon.mk gen/flashpatches.mk + $(Q)cp $(FW_PATH)/$(RAM_FILE) $@ + @printf "\033[0;31m APPLYING FLASHPATCHES\033[0m gen/flashpatches.mk => %s (details: log/flashpatches.log)\n" $@ + $(Q)make -f gen/flashpatches.mk >>log/flashpatches.log 2>>log/flashpatches.log + @printf "\033[0;31m APPLYING PATCHES\033[0m gen/nexmon.mk => %s (details: log/patches.log)\n" $@ + $(Q)make -f gen/nexmon.mk >>log/patches.log 2>>log/flashpatches.log + +################################################################### +# ucode compression related +################################################################### + +gen/ucode.asm: $(FW_PATH)/ucode.bin + @printf "\033[0;31m DISASSEMBLING UCODE\033[0m %s => %s\n" $< $@ + $(Q)$(NEXMON_ROOT)/buildtools/b43/disassembler/b43-dasm $< $@ --arch 15 --format raw-le32 + $(Q)$(NEXMON_ROOT)/buildtools/b43/debug/b43-beautifier --asmfile $@ --defs $(NEXMON_ROOT)/buildtools/b43/debug/include > tmp && mv tmp $@ + $(Q)cat $@ | gcc -fpreprocessed -dD -E - > tmp && mv tmp $@ + $(Q)sed -i '/^$$/d' $@ + $(Q)sed -i '/""/d' $@ + $(Q)sed -i -r 's|(mov )(0x48)(, SPR_TME_VAL12)|\1MAC_SUBTYPE_DATA_NULL\3|' gen/ucode.asm + $(Q)sed -i -r 's|(mov )(0xC4)(, SPR_TME_VAL12)|\1MAC_SUBTYPE_CONTROL_CTS\3|' gen/ucode.asm + $(Q)sed -i -r 's|(mov )(0xD4)(, SPR_TME_VAL12)|\1MAC_SUBTYPE_CONTROL_ACK\3|' gen/ucode.asm + $(Q)sed -i -r 's|\[0x848\]|\[RX_HDR_RxStatus1\]|g' gen/ucode.asm + $(Q)sed -i -r 's|\[0x84B\]|\[RX_HDR_RxChan\]|g' gen/ucode.asm + $(Q)sed -i -r 's|\[0x849\]|\[RX_HDR_RxStatus2\]|g' gen/ucode.asm + $(Q)sed -i -r 's|\[0x84A\]|\[RX_HDR_RxTSFTime\]|g' gen/ucode.asm + $(Q)sed -i -r 's|\[0x842\]|\[RX_HDR_PhyRxStatus_0\]|g' gen/ucode.asm + $(Q)sed -i -r 's|\[0x843\]|\[RX_HDR_PhyRxStatus_1\]|g' gen/ucode.asm + $(Q)sed -i -r 's|\[0x844\]|\[RX_HDR_PhyRxStatus_2\]|g' gen/ucode.asm + $(Q)sed -i -r 's|\[0x845\]|\[RX_HDR_PhyRxStatus_3\]|g' gen/ucode.asm + $(Q)sed -i -r 's|\[0x846\]|\[RX_HDR_PhyRxStatus_4\]|g' gen/ucode.asm + $(Q)sed -i -r 's|\[0x847\]|\[RX_HDR_PhyRxStatus_5\]|g' gen/ucode.asm + $(Q)sed -i -r 's|\[0x840\]|\[RX_HDR_RxFrameSize\]|g' gen/ucode.asm + +src/%.asm: src/%.patch gen/ucode.asm + @printf "\033[0;31m PATCHING UCODE\033[0m %s => %s\n" $< $@ + $(Q)cp gen/ucode.asm $@ + $(Q)patch -p1 $@ $< >log/patch.log || true + +ifneq ($(wildcard src/$(UCODEFILE) src/$(UCODEFILE:.asm=.patch)), ) +gen/ucode.bin: src/$(UCODEFILE) + @printf "\033[0;31m ASSEMBLING UCODE\033[0m %s => %s\n" $< $@ + +ifneq ($(wildcard $(NEXMON_ROOT)/buildtools/b43/assembler/b43-asm.bin), ) + $(Q)PATH=$(PATH):$(NEXMON_ROOT)/buildtools/b43/assembler $(NEXMON_ROOT)/buildtools/b43/assembler/b43-asm $< $@ --format raw-le32 +else + $(error Warning: please compile b43-asm.bin first) +endif + +else +gen/ucode.bin: $(FW_PATH)/ucode.bin + @printf "\033[0;31m COPYING UCODE\033[0m %s => %s\n" $< $@ + $(Q)cp $< $@ +endif + +gen/ucode_compressed.bin: gen/ucode.bin + @printf "\033[0;31m COMPRESSING UCODE\033[0m %s => %s\n" $< $@ + $(Q)cat $< | $(ZLIBFLATE) > $@ + +src/ucode_compressed.c: gen/ucode_compressed.bin + @printf "\033[0;31m GENERATING C FILE\033[0m %s => %s\n" $< $@ + $(Q)printf "#pragma NEXMON targetregion \"ucode\"\n\n" > $@ + $(Q)cd $(dir $<) && xxd -i $(notdir $<) >> $(shell pwd)/$@ + +src/templateram.c: $(FW_PATH)/templateram.bin + @printf "\033[0;31m GENERATING C FILE\033[0m %s => %s\n" $< $@ + $(Q)printf "#pragma NEXMON targetregion \"ucode\"\n\n" > $@ + $(Q)cd $(dir $<) && xxd -i $(notdir $<) >> $(shell pwd)/$@ + +################################################################### + +check-nexmon-setup-env: +ifndef NEXMON_SETUP_ENV + $(error run 'source setup_env.sh' first in the repository\'s root directory) +endif + +install-firmware: fw_bcmdhd.bin + @printf "\033[0;31m REMOUNTING /system\033[0m\n" + $(Q)adb $(ADBFLAGS) shell 'su -c "mount -o rw,remount /system"' + @printf "\033[0;31m COPYING TO PHONE\033[0m %s => /sdcard/%s\n" $< $< + $(Q)adb $(ADBFLAGS) push $< /sdcard/ >> log/adb.log 2>> log/adb.log + @printf "\033[0;31m COPYING\033[0m /sdcard/fw_bcmdhd.bin => /vendor/firmware/fw_bcmdhd.bin\n" + $(Q)adb $(ADBFLAGS) shell 'su -c "rm /vendor/firmware/fw_bcmdhd.bin && cp /sdcard/fw_bcmdhd.bin /vendor/firmware/fw_bcmdhd.bin"' + @printf "\033[0;31m RELOADING FIRMWARE\033[0m\n" + $(Q)adb $(ADBFLAGS) shell 'su -c "ifconfig wlan0 down && ifconfig wlan0 up"' + +backup-firmware: FORCE + adb $(ADBFLAGS) shell 'su -c "cp /vendor/firmware/fw_bcmdhd.bin /sdcard/fw_bcmdhd.orig.bin"' + adb $(ADBFLAGS) pull /sdcard/fw_bcmdhd.orig.bin + +install-backup: fw_bcmdhd.orig.bin + adb $(ADBFLAGS) shell 'su -c "mount -o rw,remount /system"' && \ + adb $(ADBFLAGS) push $< /sdcard/ && \ + adb $(ADBFLAGS) shell 'su -c "cp /sdcard/fw_bcmdhd.bin /vendor/firmware/fw_bcmdhd.bin"' + adb $(ADBFLAGS) shell 'su -c "ifconfig wlan0 down && ifconfig wlan0 up"' + +clean-firmware: FORCE + @printf "\033[0;31m CLEANING\033[0m\n" + $(Q)rm -fr fw_bcmdhd.bin obj gen log src/ucode_compressed.c src/templateram.c + +clean: clean-firmware + $(Q)rm -f BUILD_NUMBER + +FORCE: diff --git a/README.md b/README.md new file mode 100644 index 0000000..fe2d26d --- /dev/null +++ b/README.md @@ -0,0 +1,96 @@ +![NexMon logo](https://github.com/seemoo-lab/nexmon/raw/master/gfx/nexmon.png) + +# Nexmon Channel State Information Extractor + +This projects allows you to extract channel state information (CSI) of OFDM-modulated +Wi-Fi frames (802.11a/(g)/n/ac) on a per frame basis with up to 80 MHz bandwidth +using BCM4339 Wi-Fi chips installed, for example, in Nexus 5 smartphones. + +``` +echo "64d0010080000000ffffffffffff001122334455" | xxd -r -p | base64 +``` + +# Extract from our License + +Any use of the Software which results in an academic publication or +other publication which includes a bibliography must include +citations to the nexmon project a) and the paper cited under b) or +the thesis cited under c): + + a) "Matthias Schulz, Daniel Wegemer and Matthias Hollick. Nexmon: + The C-based Firmware Patching Framework. https://nexmon.org" + + b) "Matthias Schulz, Jakob Link, Francesco Gringoli, and Matthias + Hollick. Shadow Wi-Fi: Teaching Smartphones to Transmit Raw + Signals and to Extract Channel State Information to Implement + Practical Covert Channels over Wi-Fi. Accepted to appear in + Proceedings of the 16th ACM International Conference on Mobile + Systems, Applications, and Services (MobiSys 2018), June 2018." + + c) "Matthias Schulz. Teaching Your Wireless Card New Tricks: + Smartphone Performance and Security Enhancements through Wi-Fi + Firmware Modifications. Dr.-Ing. thesis, Technische Universität + Darmstadt, Germany, February 2018." + +# Getting Started + +To compile the source code, you are required to first clone the original nexmon repository +that contains our C-based patching framework for Wi-Fi firmwares. Than you clone this +repository as one of the sub-projects in the corresponding patches sub-directory. This +allows you to build and compile all the firmware patches required to repeat our experiments. +The following steps will get you started on Xubuntu 16.04 LTS: + +1. Install some dependencies: `sudo apt-get install git gawk qpdf adb` +2. **Only necessary for x86_64 systems**, install i386 libs: + + ``` + sudo dpkg --add-architecture i386 + sudo apt-get update + sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 + ``` +3. Clone the nexmon base repository: `git clone https://github.com/seemoo-lab/nexmon.git`. +4. Download and extract Android NDK r11c (use exactly this version!). +5. Export the NDK_ROOT environment variable pointing to the location where you extracted the + ndk so that it can be found by our build environment. +6. Navigate to the previously cloned nexmon directory and execute `source setup_env.sh` to set + a couple of environment variables. +7. Run `make` to extract ucode, templateram and flashpatches from the original firmwares. +8. Navigate to utilities and run `make` to build all utilities such as nexmon. +9. Attach your rooted Nexus 5 smartphone running stock firmware version 6.0.1 (M4B30Z, Dec 2016). +10. Run `make install` to install all the built utilities on your phone. +11. Navigate to patches/bcm4339/6_37_34_43/ and clone this repository: + `git clone https://github.com/seemoo-lab/mobisys2018_nexmon_channel_state_information_extractor.git` +12. Enter the created subdirectory mobisys2018_nexmon_channel_state_information_extractor and run + `make install-firmware` to compile our firmware patch and install it on the attached Nexus 5 + smartphone. + +# References + +* Matthias Schulz, Daniel Wegemer and Matthias Hollick. **Nexmon: The C-based Firmware Patching + Framework**. https://nexmon.org +* Matthias Schulz, Jakob Link, Francesco Gringoli, and Matthias Hollick. **Shadow Wi-Fi: Teaching + Smartphones to Transmit Raw Signals and to Extract Channel State Information to Implement + Practical Covert Channels over Wi-Fi. Accepted to appear in *Proceedings of the 16th ACM + International Conference on Mobile Systems, Applications, and Services*, MobiSys 2018, June 2018. +* Matthias Schulz. **Teaching Your Wireless Card New Tricks: Smartphone Performance and Security + Enhancements through Wi-Fi Firmware Modifications**. Dr.-Ing. thesis, Technische Universität + Darmstadt, Germany, February 2018. + +[Get references as bibtex file](https://nexmon.org/bib) + +# Contact + +* [Matthias Schulz](https://seemoo.tu-darmstadt.de/mschulz) + +# Powered By + +## Secure Mobile Networking Lab (SEEMOO) +![SEEMOO logo](https://github.com/seemoo-lab/nexmon/raw/master/gfx/seemoo.png) +## Networked Infrastructureless Cooperation for Emergency Response (NICER) +![NICER logo](https://github.com/seemoo-lab/nexmon/raw/master/gfx/nicer.png) +## Multi-Mechanisms Adaptation for the Future Internet (MAKI) +![MAKI logo](https://github.com/seemoo-lab/nexmon/raw/master/gfx/maki.png) +## Technische Universität Darmstadt +![TU Darmstadt logo](https://github.com/seemoo-lab/nexmon/raw/master/gfx/tudarmstadt.png) +## University of Brescia +![University of Brescia logo](https://github.com/seemoo-lab/nexmon/raw/master/gfx/brescia.png) diff --git a/include/macros.inc b/include/macros.inc new file mode 100644 index 0000000..4a817a6 --- /dev/null +++ b/include/macros.inc @@ -0,0 +1,43 @@ +#ifndef MACROS_INC_ +#define MACROS_INC_ + +#define phy_reg_read(addr, target) \ + mov addr, r33 \ + calls L52 \ + or SPR_Ext_IHR_Data, 0x0, target + +#define phy_reg_read_to_shm(addr, target) \ + mov addr, r33 \ + calls L52 \ + or SPR_Ext_IHR_Data, 0x0, [target] + +#define phy_reg_read_to_shm_off(addr, base, offset) \ + mov addr, r33 \ + calls L52 \ + or SPR_Ext_IHR_Data, 0x0, [base, offset] + +#define phy_reg_write(addr, value) \ + mov addr, r33 \ + mov value, r34 \ + calls L54 + +#define phy_reg_or(addr, value) \ + mov addr, r33 \ + calls L52 \ + mov value, r34 \ + or SPR_Ext_IHR_Data, r34, r34 \ + calls L54 + +#define phy_reg_and(addr, value) \ + mov addr, r33 \ + calls L52 \ + mov value, r34 \ + and SPR_Ext_IHR_Data, r34, r34 \ + calls L54 + +#define phy_table_write_word(id, offset, data) \ + phy_reg_write(ACPHY_TableID(rev), id) \ + phy_reg_write(ACPHY_TableOffset(rev), offset) \ + phy_reg_write(ACPHY_TableDataLo(rev), data) + +#endif /* MACROS_INC_ */ diff --git a/include/rxhdrlen.h b/include/rxhdrlen.h new file mode 100644 index 0000000..7c7b44b --- /dev/null +++ b/include/rxhdrlen.h @@ -0,0 +1,38 @@ +/*************************************************************************** + * * + * ########### ########### ########## ########## * + * ############ ############ ############ ############ * + * ## ## ## ## ## ## ## * + * ## ## ## ## ## ## ## * + * ########### #### ###### ## ## ## ## ###### * + * ########### #### # ## ## ## ## # # * + * ## ## ###### ## ## ## ## # # * + * ## ## # ## ## ## ## # # * + * ############ ##### ###### ## ## ## ##### ###### * + * ########### ########### ## ## ## ########## * + * * + * S E C U R E M O B I L E N E T W O R K I N G * + * * + * This file is part of NexMon. * + * * + * Copyright (c) 2016 NexMon Team * + * * + * NexMon is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * NexMon is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with NexMon. If not, see . * + * * + **************************************************************************/ + +// rx header length in words +#define RX_HDR_LEN 32 +// additional words used for wlc_d11rxhdr that is not contained in d11rxhdr +#define RX_HDR_EXTRA 8 \ No newline at end of file diff --git a/patch.ld b/patch.ld new file mode 100644 index 0000000..0fbd559 --- /dev/null +++ b/patch.ld @@ -0,0 +1,10 @@ +MEMORY +{ + INCLUDE gen/memory.ld +} + +SECTIONS +{ + INCLUDE gen/flashpatches.ld + INCLUDE gen/nexmon.ld +} diff --git a/src/csi_extraction.c b/src/csi_extraction.c new file mode 100644 index 0000000..91f3e19 --- /dev/null +++ b/src/csi_extraction.c @@ -0,0 +1,234 @@ +/*************************************************************************** + * * + * ########### ########### ########## ########## * + * ############ ############ ############ ############ * + * ## ## ## ## ## ## ## * + * ## ## ## ## ## ## ## * + * ########### #### ###### ## ## ## ## ###### * + * ########### #### # ## ## ## ## # # * + * ## ## ###### ## ## ## ## # # * + * ## ## # ## ## ## ## # # * + * ############ ##### ###### ## ## ## ##### ###### * + * ########### ########### ## ## ## ########## * + * * + * S E C U R E M O B I L E N E T W O R K I N G * + * * + * Warning: * + * * + * Our software may damage your hardware and may void your hardware’s * + * warranty! You use our tools at your own risk and responsibility! * + * * + * License: * + * Copyright (c) 2015 NexMon Team * + * * + * Permission is hereby granted, free of charge, to any person obtaining * + * a copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * Any use of the Software which results in an academic publication or * + * other publication which includes a bibliography must include a citation * + * to the author's publication "M. Schulz, D. Wegemer and M. Hollick. * + * NexMon: A Cookbook for Firmware Modifications on Smartphones to Enable * + * Monitor Mode.". * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + **************************************************************************/ + +#pragma NEXMON targetregion "patch" + +#include // definition of firmware version macros +#include // wrapper definitions for functions that already exist in the firmware +#include // structures that are used by the code in the firmware +#include // useful helper functions +#include // macros used to craete patches such as BLPatch, BPatch, ... +#include // contains RX_HDR_LEN and RX_HDR_EXTRA +#include +#include // ioctls added in the nexmon patch +#include + +extern void prepend_ethernet_ipv4_udp_header(struct sk_buff *p); + +#define WL_RSSI_ANT_MAX 4 /* max possible rx antennas */ + +// header of csi frame coming from ucode +struct d11csihdr { + uint16 RxFrameSize; /* 0x000 Set to 0x2 for CSI frames */ + uint16 NexmonExt; /* 0x002 */ + uint32 csi[]; /* 0x004 Array of CSI data */ +} __attribute__((packed)); + +// original hardware header +struct d11rxhdr { + uint16 RxFrameSize; /* 0x000 Set to 0x2 for CSI frames */ + uint16 NexmonExt; /* 0x002 */ + uint16 PhyRxStatus_0; /* 0x004 PhyRxStatus 15:0 */ + uint16 PhyRxStatus_1; /* 0x006 PhyRxStatus 31:16 */ + uint16 PhyRxStatus_2; /* 0x008 PhyRxStatus 47:32 */ + uint16 PhyRxStatus_3; /* 0x00a PhyRxStatus 63:48 */ + uint16 PhyRxStatus_4; /* 0x00c PhyRxStatus 79:64 */ + uint16 PhyRxStatus_5; /* 0x00e PhyRxStatus 95:80 */ + uint16 RxStatus1; /* 0x010 MAC Rx Status */ + uint16 RxStatus2; /* 0x012 extended MAC Rx status */ + uint16 RxTSFTime; /* 0x014 RxTSFTime time of first MAC symbol + M_PHY_PLCPRX_DLY */ + uint16 RxChan; /* 0x016 gain code, channel radio code, and phy type */ +} __attribute__((packed)); + +// header or regular frame coming from ucode +struct nexmon_d11rxhdr { + struct d11rxhdr rxhdr; /* 0x000 d11rxhdr */ + uint8 SrcMac[6]; /* 0x018 source mac address */ +} __attribute__((packed)); + +// header after process_frame_hook +struct wlc_d11rxhdr { + struct d11rxhdr rxhdr; /* 0x000 d11rxhdr */ + uint32 tsf_l; /* 0x018 TSF_L reading */ + int8 rssi; /* 0x01c computed instantaneous rssi in BMAC */ + int8 rxpwr0; /* 0x01d obsoleted, place holder for legacy ROM code. use rxpwr[] */ + int8 rxpwr1; /* 0x01e obsoleted, place holder for legacy ROM code. use rxpwr[] */ + int8 do_rssi_ma; /* 0x01f do per-pkt sampling for per-antenna ma in HIGH */ + int8 rxpwr[WL_RSSI_ANT_MAX]; /* 0x020 rssi for supported antennas */ + int8 rssi_qdb; /* 0x024 qdB portion of the computed rssi */ + uint8 PAD[2]; /* 0x025 extra padding to fill up RX_HDR_EXTRA */ +} __attribute__((packed)); + +struct csi_value_i16 { + int16 i; + int16 q; +} __attribute__((packed)); + +struct csi_udp_frame { + struct ethernet_ip_udp_header hdrs; + uint32 kk1; + uint8 SrcMac[6]; + uint32 kk2; + struct csi_value_i16 csi_values[]; +} __attribute__((packed)); + +uint16 missing_csi_frames = 0; +uint16 inserted_csi_values = 0; +struct sk_buff *p_csi = 0; + +struct int14 {signed int val:14;} __attribute__((packed)); + +void +create_new_csi_frame(struct wl_info *wl, struct sk_buff *p, struct wlc_d11rxhdr *wlc_rxhdr) +{ + struct osl_info *osh = wl->wlc->osh; + + missing_csi_frames = wlc_rxhdr->rxhdr.NexmonExt; + + // create new csi frame + p_csi = pkt_buf_get_skb(osh, sizeof(struct csi_udp_frame) + missing_csi_frames * (RX_HDR_LEN * 2)); + inserted_csi_values = 0; + + struct csi_udp_frame *udpfrm = (struct csi_udp_frame *) p_csi->data; + struct nexmon_d11rxhdr *ucodefrm = (struct nexmon_d11rxhdr *) p->data; + + udpfrm->kk1 = 0x11111111; + udpfrm->kk2 = wlc_recv_compute_rspec(&wlc_rxhdr->rxhdr, p->data); + // copy mac address to new udp frame + memcpy(udpfrm->SrcMac, ucodefrm->SrcMac, sizeof(udpfrm->SrcMac)); +} + +void +process_frame_hook(struct sk_buff *p, struct wlc_d11rxhdr *wlc_rxhdr, struct wlc_hw_info *wlc_hw, int tsf_l) +{ + struct osl_info *osh = wlc_hw->wlc->osh; + struct wl_info *wl = wlc_hw->wlc->wl; + + if (p_csi == 0) { + if (wlc_rxhdr->rxhdr.RxFrameSize == 2) { + + printf("csi out of order\n"); + + pkt_buf_free_skb(osh, p, 0); // drop incoming csi frame + + return; // drop all csi frames, if no csi information required + + } else if (wlc_rxhdr->rxhdr.NexmonExt > 0) { + create_new_csi_frame(wl, p, wlc_rxhdr); + } + } else { + struct csi_udp_frame *udpfrm = (struct csi_udp_frame *) p_csi->data; + + if (wlc_rxhdr->rxhdr.RxFrameSize == 2) { + struct d11csihdr *ucodecsifrm = (struct d11csihdr *) p->data; + + missing_csi_frames--; + + struct int14 sint14; + int i; + for (i = 0; i < wlc_rxhdr->rxhdr.NexmonExt; i++) { + struct csi_value_i16 *val = &udpfrm->csi_values[inserted_csi_values]; + + val->i = sint14.val = (ucodecsifrm->csi[i] >> 14) & 0x3fff; + val->q = sint14.val = ucodecsifrm->csi[i] & 0x3fff; + + inserted_csi_values++; + } + + if (missing_csi_frames == 0) { + + // as prepend_ethernet_ipv4_udp_header pushes, we need to pull first + p_csi->len = sizeof(struct csi_udp_frame) + inserted_csi_values * sizeof(struct csi_value_i16); + + skb_pull(p_csi, sizeof(struct ethernet_ip_udp_header)); + prepend_ethernet_ipv4_udp_header(p_csi); + + wl->dev->chained->funcs->xmit(wl->dev, wl->dev->chained, p_csi); + + p_csi = 0; + } + + pkt_buf_free_skb(osh, p, 0); // drop incoming csi frame + + return; + + } else { + printf("csi missing, size: %d\n", wlc_rxhdr->rxhdr.RxFrameSize); + + pkt_buf_free_skb(osh, p_csi, 0); + if (wlc_rxhdr->rxhdr.NexmonExt > 0) { + create_new_csi_frame(wl, p, wlc_rxhdr); + } + } + } + + // only continue processing this frame, if it is not a csi frame + wlc_rxhdr->tsf_l = tsf_l; + wlc_phy_rssi_compute(wlc_hw->band->pi, wlc_rxhdr); + + wlc_recv(wlc_hw->wlc, p); +} + +// hook to allow handling the wlc_d11rxhdr on our own to avoid overwriting of additional information in d11rxhdr passed from the ucode +__attribute__((at(0x1AAFCC, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) +__attribute__((naked)) +void +process_frame_prehook(void) +{ + asm( + "mov r2, r4\n" // 2 bytes: move wlc_hw pointer to r2 + "ldr r0, [sp,0xC]\n" // 4 bytes: load reference to p into r0 + "bl process_frame_hook\n" // 4 bytes + "nop\n" // 2 bytes: to overwrite existing instruction + "nop\n" // 2 bytes: to overwrite existing instruction + "nop\n" // 2 bytes: to overwrite existing instruction + "nop\n" // 2 bytes: to overwrite existing instruction + "nop\n" // 2 bytes: to overwrite existing instruction + ); +} diff --git a/src/ioctl.c b/src/ioctl.c new file mode 100644 index 0000000..e68b12e --- /dev/null +++ b/src/ioctl.c @@ -0,0 +1,125 @@ +/*************************************************************************** + * * + * ########### ########### ########## ########## * + * ############ ############ ############ ############ * + * ## ## ## ## ## ## ## * + * ## ## ## ## ## ## ## * + * ########### #### ###### ## ## ## ## ###### * + * ########### #### # ## ## ## ## # # * + * ## ## ###### ## ## ## ## # # * + * ## ## # ## ## ## ## # # * + * ############ ##### ###### ## ## ## ##### ###### * + * ########### ########### ## ## ## ########## * + * * + * S E C U R E M O B I L E N E T W O R K I N G * + * * + * This file is part of NexMon. * + * * + * Copyright (c) 2016 NexMon Team * + * * + * NexMon is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * NexMon is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with NexMon. If not, see . * + * * + **************************************************************************/ + +#pragma NEXMON targetregion "patch" + +#include // definition of firmware version macros +#include // contains macros to access the debug hardware +#include // wrapper definitions for functions that already exist in the firmware +#include // structures that are used by the code in the firmware +#include // useful helper functions +#include // macros used to craete patches such as BLPatch, BPatch, ... +#include // rates used to build the ratespec for frame injection +#include // ioctls added in the nexmon patch +#include // version information +#include // allows to execute argprintf to print into the arg buffer +#include + +#define SHM_CSI_COLLECT 0x8b0 +#define SHM_CSI_COPIED 0x8b1 +#define CMP_FRM_CTRL_FLD 0x8b2 +#define CMP_DURATION 0x8b3 +#define CMP_DST_MAC_0 0x8b4 +#define CMP_DST_MAC_1 0x8b5 +#define CMP_DST_MAC_2 0x8b6 +#define CMP_SRC_MAC_0 0x8b7 +#define CMP_SRC_MAC_1 0x8b8 +#define CMP_SRC_MAC_2 0x8b9 + +int +wlc_ioctl_hook(struct wlc_info *wlc, int cmd, char *arg, int len, void *wlc_if) +{ + int ret = IOCTL_ERROR; + argprintf_init(arg, len); + + switch(cmd) { + case 500: // set csi_collect + { + struct params { + uint16 chanspec; + uint16 csi_collect; + uint16 cmp_frm_ctrl_fld; + uint16 cmp_duration; + uint16 cmp_dst_mac_0; + uint16 cmp_dst_mac_1; + uint16 cmp_dst_mac_2; + uint16 cmp_src_mac_0; + uint16 cmp_src_mac_1; + uint16 cmp_src_mac_2; + }; + + struct params *params = (struct params *) arg; + + // deactivate scanning + set_scansuppress(wlc, 1); + + // deactivate minimum power consumption + set_mpc(wlc, 0); + + // set the channel + set_chanspec(wlc, params->chanspec); + + if (wlc->hw->up && len > 1) { + wlc_bmac_write_shm(wlc->hw, SHM_CSI_COLLECT * 2, params->csi_collect); + wlc_bmac_write_shm(wlc->hw, CMP_FRM_CTRL_FLD * 2, params->cmp_frm_ctrl_fld); + wlc_bmac_write_shm(wlc->hw, CMP_DURATION * 2, params->cmp_duration); + wlc_bmac_write_shm(wlc->hw, CMP_DST_MAC_0 * 2, params->cmp_dst_mac_0); + wlc_bmac_write_shm(wlc->hw, CMP_DST_MAC_1 * 2, params->cmp_dst_mac_1); + wlc_bmac_write_shm(wlc->hw, CMP_DST_MAC_2 * 2, params->cmp_dst_mac_2); + wlc_bmac_write_shm(wlc->hw, CMP_SRC_MAC_0 * 2, params->cmp_src_mac_0); + wlc_bmac_write_shm(wlc->hw, CMP_SRC_MAC_1 * 2, params->cmp_src_mac_1); + wlc_bmac_write_shm(wlc->hw, CMP_SRC_MAC_2 * 2, params->cmp_src_mac_2); + ret = IOCTL_SUCCESS; + } + break; + } + + case 501: // get csi_collect + { + if (wlc->hw->up && len > 1) { + *(uint16 *) arg = wlc_bmac_read_shm(wlc->hw, SHM_CSI_COLLECT * 2); + ret = IOCTL_SUCCESS; + } + break; + } + + default: + ret = wlc_ioctl(wlc, cmd, arg, len, wlc_if); + } + + return ret; +} + +__attribute__((at(0x1F3488, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) +GenericPatch4(wlc_ioctl_hook, wlc_ioctl_hook + 1); diff --git a/src/patch.c b/src/patch.c new file mode 100644 index 0000000..4cc035a --- /dev/null +++ b/src/patch.c @@ -0,0 +1,61 @@ +/*************************************************************************** + * * + * ########### ########### ########## ########## * + * ############ ############ ############ ############ * + * ## ## ## ## ## ## ## * + * ## ## ## ## ## ## ## * + * ########### #### ###### ## ## ## ## ###### * + * ########### #### # ## ## ## ## # # * + * ## ## ###### ## ## ## ## # # * + * ## ## # ## ## ## ## # # * + * ############ ##### ###### ## ## ## ##### ###### * + * ########### ########### ## ## ## ########## * + * * + * S E C U R E M O B I L E N E T W O R K I N G * + * * + * This file is part of NexMon. * + * * + * Copyright (c) 2016 NexMon Team * + * * + * NexMon is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * NexMon is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with NexMon. If not, see . * + * * + **************************************************************************/ + +#pragma NEXMON targetregion "patch" + +#include // definition of firmware version macros +#include // contains macros to access the debug hardware +#include // wrapper definitions for functions that already exist in the firmware +#include // structures that are used by the code in the firmware +#include // useful helper functions +#include // macros used to craete patches such as BLPatch, BPatch, ... +#include // rates used to build the ratespec for frame injection +#include // capabilities included in a nexmon patch + +int capabilities = NEX_CAP_MONITOR_MODE | NEX_CAP_MONITOR_MODE_RADIOTAP | NEX_CAP_FRAME_INJECTION; + +// Hook the call to wlc_ucode_write in wlc_ucode_download +__attribute__((at(0x1F4F08, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_40_r581243))) +__attribute__((at(0x1F4F14, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) +BLPatch(wlc_ucode_write_compressed, wlc_ucode_write_compressed); + +// reduce the amount of ucode memory freed to become part of the heap +__attribute__((at(0x1816E0, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) +GenericPatch4(hndrte_reclaim_0_end, PATCHSTART); + +extern unsigned char templateram_bin[]; + +// Moving template ram to another place in the ucode region +__attribute__((at(0x185544, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) +GenericPatch4(templateram_bin, templateram_bin); diff --git a/src/regulations.c b/src/regulations.c new file mode 100644 index 0000000..b383235 --- /dev/null +++ b/src/regulations.c @@ -0,0 +1,117 @@ +/*************************************************************************** + * * + * ########### ########### ########## ########## * + * ############ ############ ############ ############ * + * ## ## ## ## ## ## ## * + * ## ## ## ## ## ## ## * + * ########### #### ###### ## ## ## ## ###### * + * ########### #### # ## ## ## ## # # * + * ## ## ###### ## ## ## ## # # * + * ## ## # ## ## ## ## # # * + * ############ ##### ###### ## ## ## ##### ###### * + * ########### ########### ## ## ## ########## * + * * + * S E C U R E M O B I L E N E T W O R K I N G * + * * + * Warning: * + * * + * Our software may damage your hardware and may void your hardware’s * + * warranty! You use our tools at your own risk and responsibility! * + * * + * License: * + * Copyright (c) 2015 NexMon Team * + * * + * Permission is hereby granted, free of charge, to any person obtaining * + * a copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * Any use of the Software which results in an academic publication or * + * other publication which includes a bibliography must include a citation * + * to the author's publication "M. Schulz, D. Wegemer and M. Hollick. * + * NexMon: A Cookbook for Firmware Modifications on Smartphones to Enable * + * Monitor Mode.". * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + **************************************************************************/ + +#pragma NEXMON targetregion "patch" + +#include +#include +#include +#include +#include + +// Nop the following call to keep user tx power targets +// Choose least of user and now combined regulatory/hw targets +// ppr_compare_min(tx_pwr_target, srom_max_txpwr); +__attribute__((at(0x1C50B8, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) +GenericPatch4(nop_ppr_compare_min, 0); + +// This allows 80 MHz channels in the 2 GHz band +int +wf_chspec_malformed_hook(unsigned short chanspec) +{ + return 0; +} + +__attribute__((at(0x13778, "flashpatch", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) +BPatch(wf_chspec_malformed_hook, wf_chspec_malformed_hook); + +unsigned short additional_valid_chanspecs[] = { + CH20MHZ_CHSPEC(1), + CH20MHZ_CHSPEC(2), + CH20MHZ_CHSPEC(3), + CH20MHZ_CHSPEC(4), + CH20MHZ_CHSPEC(5), + CH20MHZ_CHSPEC(6), + CH20MHZ_CHSPEC(7), + CH20MHZ_CHSPEC(8), + CH20MHZ_CHSPEC(9), + CH20MHZ_CHSPEC(10), + CH20MHZ_CHSPEC(11), + CH20MHZ_CHSPEC(12), + CH20MHZ_CHSPEC(13), + CH20MHZ_CHSPEC(14), + CH80MHZ_CHSPEC(6, WL_CHANSPEC_CTL_SB_L), + CH20MHZ_CHSPEC(7), + CH40MHZ_CHSPEC(7, WL_CHANSPEC_CTL_SB_L), + CH80MHZ_CHSPEC(7, WL_CHANSPEC_CTL_SB_L), + CH20MHZ_CHSPEC(44), + CH40MHZ_CHSPEC(44, WL_CHANSPEC_CTL_SB_L), + CH20MHZ_CHSPEC(100), + CH20MHZ_CHSPEC(106), + CH40MHZ_CHSPEC(106, WL_CHANSPEC_CTL_SB_L), + CH80MHZ_CHSPEC(106, WL_CHANSPEC_CTL_SB_L), + CH20MHZ_CHSPEC(120), + CH20MHZ_CHSPEC(140), +}; + +int +wlc_valid_chanspec_ext_hook(void *wlc_cm, unsigned short chanspec, int dualband) +{ + int valid = wlc_valid_chanspec_ext(wlc_cm, chanspec, dualband); + int i; + + if (!valid && dualband == 1) + for (i = 0; i < sizeof(additional_valid_chanspecs)/sizeof(additional_valid_chanspecs[0]); i++) + valid |= additional_valid_chanspecs[i] == chanspec; + + return valid; +} + +__attribute__((at(0x5BA28, "flashpatch", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) +BPatch(wlc_valid_chanspec_ext, wlc_valid_chanspec_ext_hook) diff --git a/src/rxhdrlen.c b/src/rxhdrlen.c new file mode 100644 index 0000000..c57891c --- /dev/null +++ b/src/rxhdrlen.c @@ -0,0 +1,67 @@ +/*************************************************************************** + * * + * ########### ########### ########## ########## * + * ############ ############ ############ ############ * + * ## ## ## ## ## ## ## * + * ## ## ## ## ## ## ## * + * ########### #### ###### ## ## ## ## ###### * + * ########### #### # ## ## ## ## # # * + * ## ## ###### ## ## ## ## # # * + * ## ## # ## ## ## ## # # * + * ############ ##### ###### ## ## ## ##### ###### * + * ########### ########### ## ## ## ########## * + * * + * S E C U R E M O B I L E N E T W O R K I N G * + * * + * Warning: * + * * + * Our software may damage your hardware and may void your hardware’s * + * warranty! You use our tools at your own risk and responsibility! * + * * + * License: * + * Copyright (c) 2015 NexMon Team * + * * + * Permission is hereby granted, free of charge, to any person obtaining * + * a copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute copies of the Software, and to permit persons to whom the * + * Software is furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * Any use of the Software which results in an academic publication or * + * other publication which includes a bibliography must include a citation * + * to the author's publication "M. Schulz, D. Wegemer and M. Hollick. * + * NexMon: A Cookbook for Firmware Modifications on Smartphones to Enable * + * Monitor Mode.". * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + **************************************************************************/ + +#pragma NEXMON targetregion "patch" + +#include // definition of firmware version macros +#include // wrapper definitions for functions that already exist in the firmware +#include // structures that are used by the code in the firmware +#include // useful helper functions +#include // macros used to craete patches such as BLPatch, BPatch, ... +#include // contains RX_HDR_LEN and RX_HDR_EXTRA + +__attribute__((at(0x1F580C, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) +GenericPatch2(hwrxoff, 0x2300 + 2 * (RX_HDR_LEN + RX_HDR_EXTRA)); + +// Change the rxhdr_len in the initvals +__attribute__((at(0x1D4370, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) +GenericPatch4(initvals_rxhdr_len0, 2 * RX_HDR_LEN); + +__attribute__((at(0x1D4388, "", CHIP_VER_BCM4339, FW_VER_6_37_32_RC23_34_43_r639704))) +GenericPatch4(initvals_rxhdr_len1, 2 * RX_HDR_LEN); \ No newline at end of file diff --git a/src/ucode.patch b/src/ucode.patch new file mode 100644 index 0000000..adcc1e3 --- /dev/null +++ b/src/ucode.patch @@ -0,0 +1,318 @@ +--- ../gen/ucode.asm 2018-03-12 23:32:43.152016700 +0100 ++++ ucode.asm 2018-03-12 23:32:50.777878856 +0100 +@@ -3,0 +4,37 @@ ++#include "../include/macros.inc" ++#define phy_reg_read_to_shm(addr,target) \ ++ mov addr, r33 \ ++ calls L52 \ ++ or SPR_Ext_IHR_Data, 0x0, [target] ++#define phy_reg_write(addr,value) \ ++ mov addr, r33 \ ++ mov value, r34 \ ++ calls L54 ++#define RX_HDR_LEN 32 ++#define RX_HDR_BASE 0x8c0 ++#define RX_HDR_OFFSET(off) (RX_HDR_BASE + off) ++#define RX_HDR_RxFrameSize RX_HDR_OFFSET(0) ++#define RX_HDR_NexmonExt RX_HDR_OFFSET(1) ++#define RX_HDR_PhyRxStatus_0 RX_HDR_OFFSET(2) ++#define RX_HDR_PhyRxStatus_1 RX_HDR_OFFSET(3) ++#define RX_HDR_PhyRxStatus_2 RX_HDR_OFFSET(4) ++#define RX_HDR_PhyRxStatus_3 RX_HDR_OFFSET(5) ++#define RX_HDR_PhyRxStatus_4 RX_HDR_OFFSET(6) ++#define RX_HDR_PhyRxStatus_5 RX_HDR_OFFSET(7) ++#define RX_HDR_RxStatus1 RX_HDR_OFFSET(8) ++#define RX_HDR_RxStatus2 RX_HDR_OFFSET(9) ++#define RX_HDR_RxTSFTime RX_HDR_OFFSET(10) ++#define RX_HDR_RxChan RX_HDR_OFFSET(11) ++#define RX_HDR_NEXMON_SrcMac0 RX_HDR_OFFSET(12) ++#define RX_HDR_NEXMON_SrcMac1 RX_HDR_OFFSET(13) ++#define RX_HDR_NEXMON_SrcMac2 RX_HDR_OFFSET(14) ++#define SHM_CSI_COLLECT 0x8b0 ++#define SHM_CSI_COPIED 0x8b1 ++#define CMP_FRM_CTRL_FLD 0x8b2 ++#define CMP_DURATION 0x8b3 ++#define CMP_DST_MAC_0 0x8b4 ++#define CMP_DST_MAC_1 0x8b5 ++#define CMP_DST_MAC_2 0x8b6 ++#define CMP_SRC_MAC_0 0x8b7 ++#define CMP_SRC_MAC_1 0x8b8 ++#define CMP_SRC_MAC_2 0x8b9 +@@ -2708,0 +2746 @@ ++ mov 0, [SHM_CSI_COPIED] +@@ -2853,0 +2892,222 @@ ++#define SPIN_LENGTH (6 + 16) ++#define SPARE1 r54 ++spin_rx_header: ++ jext COND_RX_COMPLETE, spin_rx_end ++ jl SPR_RXE_FRAMELEN, SPIN_LENGTH, spin_rx_header ++spin_rx_end: ++ jl SPR_RXE_FRAMELEN, SPIN_LENGTH, skip+ ++ mov 0, r55 ++ mov [CMP_FRM_CTRL_FLD], SPARE1 ++ jne [3,off1], SPARE1, skip+ ++ mov [CMP_DURATION], SPARE1 ++ jne [4,off1], SPARE1, skip+ ++ mov [CMP_DST_MAC_0], SPARE1 ++ jne [5,off1], SPARE1, skip+ ++ mov [CMP_DST_MAC_1], SPARE1 ++ jne [6,off1], SPARE1, skip+ ++ mov [CMP_DST_MAC_2], SPARE1 ++ jne [7,off1], SPARE1, skip+ ++ mov [CMP_SRC_MAC_0], SPARE1 ++ jne [8,off1], SPARE1, skip+ ++ mov [CMP_SRC_MAC_1], SPARE1 ++ jne [9,off1], SPARE1, skip+ ++ mov [CMP_SRC_MAC_2], SPARE1 ++ jne [10,off1], SPARE1, skip+ ++ mov 1, r55 ++ jext COND_RX_COMPLETE, skip+ ++ jne [SHM_CSI_COLLECT], 1, skip+ ++ and SPR_RXE_PHYRXSTAT0, 0x3, SPARE1 ++ jne r23, 0x0, localskip+ ++ add [0x8bd], 1, [0x8bd] ++localskip: ++ jne r23, 0x1, localskip+ ++ add [0x8be], 1, [0x8be] ++localskip: ++ jne r23, 0x2, localskip+ ++ add [0x8bf], 1, [0x8bf] ++localskip: ++ or [8,off1], 0x0, [RX_HDR_NEXMON_SrcMac0] ++ or [9,off1], 0x0, [RX_HDR_NEXMON_SrcMac1] ++ or [10,off1], 0x0, [RX_HDR_NEXMON_SrcMac2] ++ je r23, 0x0, skip+ ++ mov RX_HDR_BASE + RX_HDR_LEN, SPARE1 ++ mov RX_HDR_BASE + (17 * RX_HDR_LEN), SPR_BASE5 ++erase_hdr: ++ mov 0x0, [0x00,off5] ++ sub SPR_BASE5, 0x1, SPR_BASE5 ++ jges SPR_BASE5, SPARE1, erase_hdr- ++ phy_reg_write(0x00d,73) ++ mov 0, SPARE1 ++ mov (RX_HDR_BASE + RX_HDR_LEN), SPR_BASE5 ++ or 2, 0x0, [0, off5] ++ or 15, 0x0, [1, off5] ++ add SPR_BASE5, 2, SPR_BASE5 ++repeat: ++ phy_reg_write(0x00e, SPARE1) ++ phy_reg_read_to_shm_off(0x00f, 0, off5) ++ phy_reg_read_to_shm_off(0x010, 1, off5) ++ add SPR_BASE5, 2, SPR_BASE5 ++ add SPARE1, 1, SPARE1 ++ jl SPARE1, 15, repeat- ++ or 2, 0x0, [0, off5] ++ or 15, 0x0, [1, off5] ++ add SPR_BASE5, 2, SPR_BASE5 ++repeat: ++ phy_reg_write(0x00e, SPARE1) ++ phy_reg_read_to_shm_off(0x00f, 0, off5) ++ phy_reg_read_to_shm_off(0x010, 1, off5) ++ add SPR_BASE5, 2, SPR_BASE5 ++ add SPARE1, 1, SPARE1 ++ jl SPARE1, 30, repeat- ++ or 2, 0x0, [0, off5] ++ or 15, 0x0, [1, off5] ++ add SPR_BASE5, 2, SPR_BASE5 ++repeat: ++ phy_reg_write(0x00e, SPARE1) ++ phy_reg_read_to_shm_off(0x00f, 0, off5) ++ phy_reg_read_to_shm_off(0x010, 1, off5) ++ add SPR_BASE5, 2, SPR_BASE5 ++ add SPARE1, 1, SPARE1 ++ jl SPARE1, 45, repeat- ++ or 2, 0x0, [0, off5] ++ or 15, 0x0, [1, off5] ++ add SPR_BASE5, 2, SPR_BASE5 ++repeat: ++ phy_reg_write(0x00e, SPARE1) ++ phy_reg_read_to_shm_off(0x00f, 0, off5) ++ phy_reg_read_to_shm_off(0x010, 1, off5) ++ add SPR_BASE5, 2, SPR_BASE5 ++ add SPARE1, 1, SPARE1 ++ jl SPARE1, 60, repeat- ++ or 2, 0x0, [0, off5] ++ or 15, 0x0, [1, off5] ++ add SPR_BASE5, 2, SPR_BASE5 ++repeat: ++ phy_reg_write(0x00e, SPARE1) ++ phy_reg_read_to_shm_off(0x00f, 0, off5) ++ phy_reg_read_to_shm_off(0x010, 1, off5) ++ add SPR_BASE5, 2, SPR_BASE5 ++ add SPARE1, 1, SPARE1 ++ jl SPARE1, 75, repeat- ++ or 2, 0x0, [0, off5] ++ or 15, 0x0, [1, off5] ++ add SPR_BASE5, 2, SPR_BASE5 ++repeat: ++ phy_reg_write(0x00e, SPARE1) ++ phy_reg_read_to_shm_off(0x00f, 0, off5) ++ phy_reg_read_to_shm_off(0x010, 1, off5) ++ add SPR_BASE5, 2, SPR_BASE5 ++ add SPARE1, 1, SPARE1 ++ jl SPARE1, 90, repeat- ++ or 2, 0x0, [0, off5] ++ or 15, 0x0, [1, off5] ++ add SPR_BASE5, 2, SPR_BASE5 ++repeat: ++ phy_reg_write(0x00e, SPARE1) ++ phy_reg_read_to_shm_off(0x00f, 0, off5) ++ phy_reg_read_to_shm_off(0x010, 1, off5) ++ add SPR_BASE5, 2, SPR_BASE5 ++ add SPARE1, 1, SPARE1 ++ jl SPARE1, 105, repeat- ++ or 2, 0x0, [0, off5] ++ or 15, 0x0, [1, off5] ++ add SPR_BASE5, 2, SPR_BASE5 ++repeat: ++ phy_reg_write(0x00e, SPARE1) ++ phy_reg_read_to_shm_off(0x00f, 0, off5) ++ phy_reg_read_to_shm_off(0x010, 1, off5) ++ add SPR_BASE5, 2, SPR_BASE5 ++ add SPARE1, 1, SPARE1 ++ jl SPARE1, 120, repeat- ++ or 2, 0x0, [0, off5] ++ or 15, 0x0, [1, off5] ++ add SPR_BASE5, 2, SPR_BASE5 ++repeat: ++ phy_reg_write(0x00e, SPARE1) ++ phy_reg_read_to_shm_off(0x00f, 0, off5) ++ phy_reg_read_to_shm_off(0x010, 1, off5) ++ add SPR_BASE5, 2, SPR_BASE5 ++ add SPARE1, 1, SPARE1 ++ jl SPARE1, 135, repeat- ++ or 2, 0x0, [0, off5] ++ or 15, 0x0, [1, off5] ++ add SPR_BASE5, 2, SPR_BASE5 ++repeat: ++ phy_reg_write(0x00e, SPARE1) ++ phy_reg_read_to_shm_off(0x00f, 0, off5) ++ phy_reg_read_to_shm_off(0x010, 1, off5) ++ add SPR_BASE5, 2, SPR_BASE5 ++ add SPARE1, 1, SPARE1 ++ jl SPARE1, 150, repeat- ++ or 2, 0x0, [0, off5] ++ or 15, 0x0, [1, off5] ++ add SPR_BASE5, 2, SPR_BASE5 ++repeat: ++ phy_reg_write(0x00e, SPARE1) ++ phy_reg_read_to_shm_off(0x00f, 0, off5) ++ phy_reg_read_to_shm_off(0x010, 1, off5) ++ add SPR_BASE5, 2, SPR_BASE5 ++ add SPARE1, 1, SPARE1 ++ jl SPARE1, 165, repeat- ++ or 2, 0x0, [0, off5] ++ or 15, 0x0, [1, off5] ++ add SPR_BASE5, 2, SPR_BASE5 ++repeat: ++ phy_reg_write(0x00e, SPARE1) ++ phy_reg_read_to_shm_off(0x00f, 0, off5) ++ phy_reg_read_to_shm_off(0x010, 1, off5) ++ add SPR_BASE5, 2, SPR_BASE5 ++ add SPARE1, 1, SPARE1 ++ jl SPARE1, 180, repeat- ++ or 2, 0x0, [0, off5] ++ or 15, 0x0, [1, off5] ++ add SPR_BASE5, 2, SPR_BASE5 ++repeat: ++ phy_reg_write(0x00e, SPARE1) ++ phy_reg_read_to_shm_off(0x00f, 0, off5) ++ phy_reg_read_to_shm_off(0x010, 1, off5) ++ add SPR_BASE5, 2, SPR_BASE5 ++ add SPARE1, 1, SPARE1 ++ jl SPARE1, 195, repeat- ++ or 2, 0x0, [0, off5] ++ or 15, 0x0, [1, off5] ++ add SPR_BASE5, 2, SPR_BASE5 ++repeat: ++ phy_reg_write(0x00e, SPARE1) ++ phy_reg_read_to_shm_off(0x00f, 0, off5) ++ phy_reg_read_to_shm_off(0x010, 1, off5) ++ add SPR_BASE5, 2, SPR_BASE5 ++ add SPARE1, 1, SPARE1 ++ jl SPARE1, 210, repeat- ++ or 2, 0x0, [0, off5] ++ or 15, 0x0, [1, off5] ++ add SPR_BASE5, 2, SPR_BASE5 ++repeat: ++ phy_reg_write(0x00e, SPARE1) ++ phy_reg_read_to_shm_off(0x00f, 0, off5) ++ phy_reg_read_to_shm_off(0x010, 1, off5) ++ add SPR_BASE5, 2, SPR_BASE5 ++ add SPARE1, 1, SPARE1 ++ jl SPARE1, 225, repeat- ++ or 2, 0x0, [0, off5] ++ or 15, 0x0, [1, off5] ++ add SPR_BASE5, 2, SPR_BASE5 ++repeat: ++ phy_reg_write(0x00e, SPARE1) ++ phy_reg_read_to_shm_off(0x00f, 0, off5) ++ phy_reg_read_to_shm_off(0x010, 1, off5) ++ add SPR_BASE5, 2, SPR_BASE5 ++ add SPARE1, 1, SPARE1 ++ jl SPARE1, 240, repeat- ++ or 2, 0x0, [0, off5] ++ or 15, 0x0, [1, off5] ++ add SPR_BASE5, 2, SPR_BASE5 ++repeat: ++ phy_reg_write(0x00e, SPARE1) ++ phy_reg_read_to_shm_off(0x00f, 0, off5) ++ phy_reg_read_to_shm_off(0x010, 1, off5) ++ add SPR_BASE5, 2, SPR_BASE5 ++ add SPARE1, 1, SPARE1 ++ jl SPARE1, 255, repeat- ++ mov 1, [SHM_CSI_COPIED] ++skip: +@@ -3491,0 +3752 @@ ++ je r55, 1, skip+ +@@ -3492,0 +3754,3 @@ ++ jne [SHM_CSI_COLLECT], 1, skip+ ++ jmp L720 ++skip: +@@ -3530,0 +3795,40 @@ ++ mov RX_HDR_BASE, SPR_RXE_RXHDR_OFFSET ++ or 0, 0x0, [SHM(0x1182)] ++ jne [SHM_CSI_COPIED], 1, skip+ ++ or 17, 0x0, [SHM(0x1182)] ++skip: ++ calls L798 ++ jne [SHM_CSI_COPIED], 1, skip+ ++ mov RX_HDR_BASE + RX_HDR_LEN, SPR_RXE_RXHDR_OFFSET ++ calls L798 ++ mov RX_HDR_BASE + (2 * RX_HDR_LEN), SPR_RXE_RXHDR_OFFSET ++ calls L798 ++ mov RX_HDR_BASE + (3 * RX_HDR_LEN), SPR_RXE_RXHDR_OFFSET ++ calls L798 ++ mov RX_HDR_BASE + (4 * RX_HDR_LEN), SPR_RXE_RXHDR_OFFSET ++ calls L798 ++ mov RX_HDR_BASE + (5 * RX_HDR_LEN), SPR_RXE_RXHDR_OFFSET ++ calls L798 ++ mov RX_HDR_BASE + (6 * RX_HDR_LEN), SPR_RXE_RXHDR_OFFSET ++ calls L798 ++ mov RX_HDR_BASE + (7 * RX_HDR_LEN), SPR_RXE_RXHDR_OFFSET ++ calls L798 ++ mov RX_HDR_BASE + (8 * RX_HDR_LEN), SPR_RXE_RXHDR_OFFSET ++ calls L798 ++ mov RX_HDR_BASE + (9 * RX_HDR_LEN), SPR_RXE_RXHDR_OFFSET ++ calls L798 ++ mov RX_HDR_BASE + (10 * RX_HDR_LEN), SPR_RXE_RXHDR_OFFSET ++ calls L798 ++ mov RX_HDR_BASE + (11 * RX_HDR_LEN), SPR_RXE_RXHDR_OFFSET ++ calls L798 ++ mov RX_HDR_BASE + (12 * RX_HDR_LEN), SPR_RXE_RXHDR_OFFSET ++ calls L798 ++ mov RX_HDR_BASE + (13 * RX_HDR_LEN), SPR_RXE_RXHDR_OFFSET ++ calls L798 ++ mov RX_HDR_BASE + (14 * RX_HDR_LEN), SPR_RXE_RXHDR_OFFSET ++ calls L798 ++ mov RX_HDR_BASE + (15 * RX_HDR_LEN), SPR_RXE_RXHDR_OFFSET ++ calls L798 ++ mov RX_HDR_BASE + (16 * RX_HDR_LEN), SPR_RXE_RXHDR_OFFSET ++ calls L798 ++ mov RX_HDR_BASE + (17 * RX_HDR_LEN), SPR_RXE_RXHDR_OFFSET +@@ -3531,0 +3836 @@ ++skip: +@@ -4474,2 +4779 @@ +- mov 0x840, SPR_RXE_RXHDR_OFFSET +- mov 0xE, SPR_RXE_RXHDR_LEN ++ mov RX_HDR_LEN, SPR_RXE_RXHDR_LEN