Skip to content

Repository files navigation

esp_wifi_usb

A driver that brings up an RTL8188EU USB Wi-Fi dongle on an ESP32-S3, using the SoC's built-in USB OTG host controller — no external USB host chip required.

The goal is a self-contained, second Wi-Fi radio for the ESP32 that behaves like esp_wifi.h: promiscuous-mode sniffing and raw 802.11 frame injection, driven entirely from a bit-level reimplementation of the Realtek rtl8188eu Linux driver's init/PHY/RF sequence (no vendor blob, no Linux kernel).

Status

  • RX / promiscuous sniffing: working. The chip's USB enumeration, firmware download, MAC/BB/RF bring-up, and calibration sequence are ported and functional; real 802.11 frames (beacons, probes, data) from nearby APs/stations are captured with plausible RSSI on the bulk-IN endpoint.
  • TX / raw frame injection: working and confirmed on air. The chip accepts injected frames, the firmware reports successful transmission (CCX TX report, pkt_ok=1), and the frames have been confirmed in the air with an external sniffer.

This started as (and largely remains) a reverse-engineering / bring-up project rather than a polished library — expect rough edges outside the core RX/TX path.

Why

The ESP32's integrated Wi-Fi radio doesn't support monitor-mode injection/reception the way a dedicated USB dongle chipset does, and most RTL8188EU support assumes a full Linux host. This project ports just enough of the real Realtek driver logic — traced from USB captures and the lwfinger/rtl8188eu Linux driver source — to run standalone on ESP-IDF's USB Host Library, using the ESP32-S3's OTG peripheral.

Hardware

  • An ESP32-S3 board with USB OTG (native USB, not just USB-UART) — developed against a generic esp32-s3-devkitc-1.
  • A USB Wi-Fi dongle based on the Realtek RTL8188EU chipset (Vendor/Product IDs matched in the USB host code).
  • A USB OTG cable/adapter to connect the dongle to the ESP32-S3's OTG port.

Building

This is a PlatformIO project targeting the espidf framework.

git clone https://github.com/Alexxdal/esp_wifi_usb.git
cd esp_wifi_usb
pio run                # build
pio run -t upload      # flash
pio device monitor      # serial log

Environment (platformio.ini):

[env:esp32s3]
platform = espressif32@^6.5.0
framework = espidf
board = esp32-s3-devkitc-1
build_type = release

Project layout

lib/esp_wifi_usb/          the driver, packaged as a PlatformIO library
  src/
    esp_wifi_usb.h/.c        public API + task/lifecycle glue
    rtl8188e_usb.c/.h        USB host (enumeration, bulk transfers, VID/PID match)
    rtl8188e_hal.c/.h        chip bring-up: power-on, firmware download, MAC init,
                              queue/LLT setup, TX/RX pipeline configuration
    rtl8188e_phy.c/.h        PHY/RF register table interpreter, channel switching
    rtl8188e_iqk.c/.h        IQ / LC calibration
    rtl8188e_rx.c/.h         RX descriptor parsing, promiscuous callback dispatch
    rtl8188e_tables.c/.h     MAC/BB/RF/AGC register tables (ported from the
                              reference driver's PHY config files)
    rtl8188e_reg.h            register and bitfield definitions
    rtl8188e_spec.h           hardware constants / descriptor layout
    rtl8188eu_fw.h            embedded chip firmware blob
  examples/usage_example.c   promiscuous sniffing + periodic beacon injection
src/main.c                  example application (same as usage_example.c)

API

The public API in esp_wifi_usb.h mirrors ESP-IDF's esp_wifi.h naming, with usb inserted after esp_wifi_, so application code looks familiar:

#include "esp_wifi_usb.h"

static void rx_cb(void *buf, wifi_promiscuous_pkt_type_t type)
{
    wifi_promiscuous_pkt_t *pkt = (wifi_promiscuous_pkt_t *)buf;
    ESP_LOGI(TAG, "ch=%u rssi=%d len=%u",
             pkt->rx_ctrl.channel, pkt->rx_ctrl.rssi, pkt->rx_ctrl.sig_len);
}

void app_main(void)
{
    esp_wifi_usb_init(15000);                       /* wait for the dongle, bring up the chip */
    esp_wifi_usb_set_promiscuous_rx_cb(rx_cb);
    esp_wifi_usb_set_promiscuous(true);
    esp_wifi_usb_set_channel(1);
    esp_wifi_usb_start();                            /* start the RX task */

    esp_wifi_usb_80211_tx(frame, frame_len, false);   /* inject a raw 802.11 frame */
}

Known limitations of the API (documented in esp_wifi_usb.h):

  • No station/AP mode — only promiscuous RX and raw frame TX (sniffing/injection only, no association).
  • esp_wifi_usb_set_promiscuous(false) pauses delivery to the callback; it does not disable the hardware's promiscuous receive filter.
  • TX power control is a single coarse "volume" (0–63 hardware index) applied uniformly across rates, with no known dBm calibration curve.
  • The channel range and 20 MHz-only bandwidth reflect the chip being 1T1R b/g/n.

How it was built

The driver logic isn't guessed — it's reconstructed by comparing this project's C code, register-by-register and bitfield-by-bitfield, against the real Realtek Linux driver (lwfinger/rtl8188eu) source, plus real USB captures of the vendor Windows driver talking to the same physical dongle. Each bring-up/debugging session's findings (bugs found, registers added, ordering fixes, things deliberately left unimplemented) are logged in detail as the work progresses, which is how issues like a byte-swapped Link List Table register and mis-ordered initialization stages were tracked down.

License

No license file is currently included in the repository; treat the code as all-rights-reserved by the author unless/until a license is added.

About

RTL8188EU USB Wi-Fi driver for ESP32-S3's native USB host — promiscuous sniffing + raw 802.11 injection.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages