espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.58k stars 7.27k forks source link

esp_wifi_80211_tx() does not work in AP mode (IDFGH-4550) #6368

Closed doragasu closed 3 years ago

doragasu commented 3 years ago

Environment

Problem Description

When using a device configured in AP mode and no STAs associated, each call to esp_wifi_80211_tx() returns ESP_OK, but the frame is not sent (I am verifying with Wireshark), and also in the logs a warning message like W (356074) wifi:conn is released is printed.

Expected Behavior

With the device configured as AP and no STAs associated, a call to esp_wifi_80211_tx() sends the frame to the air, and no warning message is printed in the log trace.

Actual Behavior

With the device configured as AP and no STAs associated, a call to esp_wifi_80211_tx() does not send the frame to the air, and a warning message wifi:conn is released is printed in the log trace.

Steps to reproduce

  1. Configure the WiFi as AP and start it. Do not associate any stations
  2. Try sending frames using esp_wifi_80211_tx()

Code to reproduce this issue

I am using a slightly modified version of this code, to update to the new event handler: https://github.com/Jeija/esp32-80211-tx

#include "freertos/FreeRTOS.h"

#include "esp_system.h"
#include "esp_event.h"
#include "esp_wifi.h"

#include "nvs_flash.h"
#include "string.h"

/*
 * This is the (currently unofficial) 802.11 raw frame TX API,
 * defined in esp32-wifi-lib's libnet80211.a/ieee80211_output.o
 *
 * This declaration is all you need for using esp_wifi_80211_tx in your own application.
 */
esp_err_t esp_wifi_80211_tx(wifi_interface_t ifx, const void *buffer, int len, bool en_sys_seq);

uint8_t beacon_raw[] = {
    0x80, 0x00,                         // 0-1: Frame Control
    0x00, 0x00,                         // 2-3: Duration
    0xff, 0xff, 0xff, 0xff, 0xff, 0xff,             // 4-9: Destination address (broadcast)
    0xba, 0xde, 0xaf, 0xfe, 0x00, 0x06,             // 10-15: Source address
    0xba, 0xde, 0xaf, 0xfe, 0x00, 0x06,             // 16-21: BSSID
    0x00, 0x00,                         // 22-23: Sequence / fragment number
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,         // 24-31: Timestamp (GETS OVERWRITTEN TO 0 BY HARDWARE)
    0x64, 0x00,                         // 32-33: Beacon interval
    0x31, 0x04,                         // 34-35: Capability info
    0x00, 0x00, /* FILL CONTENT HERE */             // 36-38: SSID parameter set, 0x00:length:content
    0x01, 0x08, 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, // 39-48: Supported rates
    0x03, 0x01, 0x01,                       // 49-51: DS Parameter set, current channel 1 (= 0x01),
    0x05, 0x04, 0x01, 0x02, 0x00, 0x00,             // 52-57: Traffic Indication Map

};

char *rick_ssids[] = {
    "01 Never gonna give you up",
    "02 Never gonna let you down",
    "03 Never gonna run around",
    "04 and desert you",
    "05 Never gonna make you cry",
    "06 Never gonna say goodbye",
    "07 Never gonna tell a lie",
    "08 and hurt you"
};

#define BEACON_SSID_OFFSET 38
#define SRCADDR_OFFSET 10
#define BSSID_OFFSET 16
#define SEQNUM_OFFSET 22
#define TOTAL_LINES (sizeof(rick_ssids) / sizeof(char *))

void spam_task(void *pvParameter) {
    uint8_t line = 0;

    // Keep track of beacon sequence numbers on a per-songline-basis
    uint16_t seqnum[TOTAL_LINES] = { 0 };

    for (;;) {
        vTaskDelay(100 / TOTAL_LINES / portTICK_PERIOD_MS);

        // Insert line of Rick Astley's "Never Gonna Give You Up" into beacon packet
        printf("%i %i %s\r\n", strlen(rick_ssids[line]), TOTAL_LINES, rick_ssids[line]);

        uint8_t beacon_rick[200];
        memcpy(beacon_rick, beacon_raw, BEACON_SSID_OFFSET - 1);
        beacon_rick[BEACON_SSID_OFFSET - 1] = strlen(rick_ssids[line]);
        memcpy(&beacon_rick[BEACON_SSID_OFFSET], rick_ssids[line], strlen(rick_ssids[line]));
        memcpy(&beacon_rick[BEACON_SSID_OFFSET + strlen(rick_ssids[line])], &beacon_raw[BEACON_SSID_OFFSET], sizeof(beacon_raw) - BEACON_SSID_OFFSET);

        // Last byte of source address / BSSID will be line number - emulate multiple APs broadcasting one song line each
        beacon_rick[SRCADDR_OFFSET + 5] = line;
        beacon_rick[BSSID_OFFSET + 5] = line;

        // Update sequence number
        beacon_rick[SEQNUM_OFFSET] = (seqnum[line] & 0x0f) << 4;
        beacon_rick[SEQNUM_OFFSET + 1] = (seqnum[line] & 0xff0) >> 4;
        seqnum[line]++;
        if (seqnum[line] > 0xfff)
            seqnum[line] = 0;

        esp_wifi_80211_tx(WIFI_IF_AP, beacon_rick, sizeof(beacon_raw) + strlen(rick_ssids[line]), false);

        if (++line >= TOTAL_LINES)
            line = 0;
    }
}

static void wifi_ap_handler(void* arg, esp_event_base_t event_base,
            int32_t event_id, void* event_data)
{
}

void app_main(void) {
    nvs_flash_init();
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
    ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_ap();
    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
                            ESP_EVENT_ANY_ID,
                            &wifi_ap_handler,
                            NULL, NULL));

    // Init dummy AP to specify a channel and get WiFi hardware into
    // a mode where we can send the actual fake beacon frames.
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    wifi_config_t ap_config = {
        .ap = {
            .ssid = "esp32-beaconspam",
            .ssid_len = 0,
            .password = "dummypassword",
            .channel = 1,
            .authmode = WIFI_AUTH_WPA2_PSK,
            .ssid_hidden = 1,
            .max_connection = 4,
            .beacon_interval = 60000
        }
    };

    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &ap_config));
    ESP_ERROR_CHECK(esp_wifi_start());
    ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));

    xTaskCreate(&spam_task, "spam_task", 2048, NULL, 5, NULL);
}

Modifying the code to work as STA instead of AP, makes it work. Also the original code at https://github.com/Jeija/esp32-80211-tx worked with earlier IDF versions (and works also on current ESP8266_RTOS_SDK v3.2), so this must be a regression.

Debug Logs

During operation of program above, logs look like this:

27 8 02 Never gonna let you down
W (129754) wifi:conn is released
25 8 03 Never gonna run around
W (129764) wifi:conn is released
17 8 04 and desert you
W (129774) wifi:conn is released
27 8 05 Never gonna make you cry
W (129784) wifi:conn is released
26 8 06 Never gonna say goodbye
W (129794) wifi:conn is released
25 8 07 Never gonna tell a lie
W (129804) wifi:conn is released
Alvin1Zhang commented 3 years ago

Thanks for reporting, we will look into.

YouDONG-ESP commented 3 years ago

Hi @doragasu, It's also a bug. Repair patch will be release soon. Thanks for reporting.

doragasu commented 3 years ago

Great, thanks for support!

Alvin1Zhang commented 3 years ago

Thanks for reporting and sorry for slow turnaround, fix on release/4.2 is available at https://github.com/espressif/esp-idf/commit/f2f42c4bfc00583e59c743583806f6cefc34b44c, feel free to reopen if the issue still happens. Thanks.