1 // Copyright 2020 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "string.h"
16 #include "esp_system.h"
17 #include "unity.h"
18 #include "esp_system.h"
19 #include "esp_event.h"
20 #include "esp_wifi_types.h"
21 #include "utils/common.h"
22 #include "common/ieee802_11_defs.h"
23 #include "../src/esp_supplicant/esp_wifi_driver.h"
24 #include "esp_log.h"
25 #include "test_utils.h"
26 #include "freertos/event_groups.h"
27
28 #define WIFI_START_EVENT 0x00000001
29 #define WIFI_ROC_DONE_EVENT 0x00000002
30 #define WIFI_ACTION_RX_EVENT 0x00000003
31 #define WIFI_SCAN_DONE_EVENT 0x00000004
32
33 #define TEST_LISTEN_CHANNEL 6
34
35 #if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32C3)
36
37 static const char *TAG = "test_offchan";
38 esp_netif_t *wifi_netif;
39 static EventGroupHandle_t wifi_event;
40
wifi_event_handler(void * arg,esp_event_base_t event_base,int32_t event_id,void * event_data)41 static void wifi_event_handler(void *arg, esp_event_base_t event_base,
42 int32_t event_id, void *event_data)
43 {
44 switch (event_id) {
45 case WIFI_EVENT_STA_START:
46 ESP_LOGI(TAG, "WIFI Started");
47 xEventGroupSetBits(wifi_event, WIFI_START_EVENT);
48 break;
49 case WIFI_EVENT_ACTION_TX_STATUS: {
50 wifi_event_action_tx_status_t *evt =
51 (wifi_event_action_tx_status_t *)event_data;
52
53 if (evt->status == 0) {
54 ESP_LOGI(TAG, "Action Tx Successful");
55 }
56 }
57 break;
58 case WIFI_EVENT_ROC_DONE:
59 ESP_LOGI(TAG, "ROC Done");
60 xEventGroupSetBits(wifi_event, WIFI_ROC_DONE_EVENT);
61 break;
62 case WIFI_EVENT_SCAN_DONE:
63 ESP_LOGI(TAG, "Scan Done");
64 xEventGroupSetBits(wifi_event, WIFI_SCAN_DONE_EVENT);
65 break;
66 default:
67 break;
68 }
69 return;
70 }
71
event_init(void)72 static esp_err_t event_init(void)
73 {
74 ESP_ERROR_CHECK(esp_event_loop_create_default());
75 ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));
76 wifi_netif = esp_netif_create_default_wifi_sta();
77
78 return ESP_OK;
79 }
80
start_wifi_as_sta(void)81 static void start_wifi_as_sta(void)
82 {
83 wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
84 cfg.nvs_enable = false;
85
86 event_init();
87
88 // can't deinit event loop, need to reset leak check
89 unity_reset_leak_checks();
90
91 if (wifi_event == NULL) {
92 wifi_event = xEventGroupCreate();
93 } else {
94 xEventGroupClearBits(wifi_event, 0x00ffffff);
95 }
96
97 TEST_ESP_OK(esp_wifi_init(&cfg));
98 TEST_ESP_OK(esp_wifi_set_mode(WIFI_MODE_STA));
99 TEST_ESP_OK(esp_wifi_start());
100
101 }
102
stop_wifi(void)103 static void stop_wifi(void)
104 {
105 esp_event_loop_delete_default();
106 ESP_LOGI(TAG, "Stop wifi\n");
107 TEST_ESP_OK(esp_wifi_stop());
108 TEST_ESP_OK(esp_wifi_deinit());
109 esp_wifi_clear_default_wifi_driver_and_handlers(wifi_netif);
110 esp_netif_destroy(wifi_netif);
111 if (wifi_event) {
112 vEventGroupDelete(wifi_event);
113 wifi_event = NULL;
114 }
115 vTaskDelay(1000 / portTICK_PERIOD_MS);
116 }
117
dummy_rx_action(uint8_t * hdr,uint8_t * payload,size_t len,uint8_t channel)118 int dummy_rx_action(uint8_t *hdr, uint8_t *payload, size_t len, uint8_t channel)
119 {
120 return ESP_OK;
121 }
122
123 static const char *frame_data = "This is a test data";
124
esp_send_action_frame(uint8_t * dest_mac,const uint8_t * buf,uint32_t len,uint8_t channel,uint32_t wait_time_ms)125 void esp_send_action_frame(uint8_t *dest_mac, const uint8_t *buf, uint32_t len,
126 uint8_t channel, uint32_t wait_time_ms)
127 {
128 wifi_action_tx_req_t *req = os_zalloc(sizeof(*req) + len);;
129 TEST_ASSERT( req != NULL);
130
131 req->ifx = ESP_IF_WIFI_STA;
132 memcpy(req->dest_mac, dest_mac, ETH_ALEN);
133 req->no_ack = false;
134 req->data_len = len;
135 req->rx_cb = dummy_rx_action;
136 memcpy(req->data, buf, req->data_len);
137
138 ESP_LOGI(TAG, "Action Tx - MAC:" MACSTR ", Channel-%d, WaitT-%d",
139 MAC2STR(dest_mac), channel, wait_time_ms);
140
141 TEST_ESP_OK(esp_wifi_action_tx_req(WIFI_OFFCHAN_TX_REQ, channel, wait_time_ms, req));
142
143 os_free(req);
144 }
145
146
147 /* Test that foreground Scan doesn't pre-empt ROC & vice versa */
148 TEST_CASE("Test scan and ROC simultaneously", "[Offchan]")
149 {
150 wifi_action_rx_cb_t rx_cb = dummy_rx_action;
151 EventBits_t bits;
152
153 test_case_uses_tcpip();
154 start_wifi_as_sta();
155
156 xEventGroupWaitBits(wifi_event, WIFI_START_EVENT, 1, 0, 5000 / portTICK_RATE_MS);
157
158 TEST_ESP_OK(esp_wifi_remain_on_channel(ESP_IF_WIFI_STA, WIFI_ROC_REQ, TEST_LISTEN_CHANNEL,
159 100, rx_cb));
160 ESP_ERROR_CHECK(esp_wifi_scan_start(NULL, false));
161 bits = xEventGroupWaitBits(wifi_event, WIFI_ROC_DONE_EVENT | WIFI_SCAN_DONE_EVENT,
162 pdTRUE, pdFALSE, 5000 / portTICK_RATE_MS);
163 TEST_ASSERT_TRUE(bits == WIFI_ROC_DONE_EVENT);
164
165 vTaskDelay(1000 / portTICK_PERIOD_MS);
166 ESP_ERROR_CHECK(esp_wifi_scan_start(NULL, false));
167 TEST_ESP_OK(esp_wifi_remain_on_channel(ESP_IF_WIFI_STA, WIFI_ROC_REQ, TEST_LISTEN_CHANNEL,
168 100, rx_cb));
169 bits = xEventGroupWaitBits(wifi_event, WIFI_ROC_DONE_EVENT | WIFI_SCAN_DONE_EVENT,
170 pdTRUE, pdFALSE, 5000 / portTICK_RATE_MS);
171 TEST_ASSERT_TRUE(bits == WIFI_SCAN_DONE_EVENT);
172
173 stop_wifi();
174 }
175
test_wifi_offchan_tx(void)176 static void test_wifi_offchan_tx(void)
177 {
178 int i;
179 char mac_str[19];
180 uint8_t mac[6];
181
182 test_case_uses_tcpip();
183 start_wifi_as_sta();
184 xEventGroupWaitBits(wifi_event, WIFI_START_EVENT, 1, 0, 5000 / portTICK_RATE_MS);
185
186 unity_wait_for_signal_param("Listener mac", mac_str, 19);
187
188 TEST_ASSERT_TRUE(unity_util_convert_mac_from_string(mac_str, mac));
189
190 for (i = 0; i < 3; i++) {
191 esp_send_action_frame(mac, (const uint8_t *)frame_data, strlen(frame_data),
192 TEST_LISTEN_CHANNEL, 500);
193 vTaskDelay(500 / portTICK_PERIOD_MS);
194 }
195
196 stop_wifi();
197 }
198
test_rx_action(uint8_t * hdr,uint8_t * payload,size_t len,uint8_t channel)199 static int test_rx_action(uint8_t *hdr, uint8_t *payload, size_t len, uint8_t channel)
200 {
201 struct ieee80211_hdr *rx_hdr = (struct ieee80211_hdr *)hdr;
202
203 ESP_LOGI(TAG, "Rxd Action Frame from " MACSTR " (Seq-%lu)", MAC2STR(rx_hdr->addr2),
204 WLAN_GET_SEQ_SEQ(rx_hdr->seq_ctrl));
205
206 if (!os_memcmp(payload, frame_data, strlen(frame_data))) {
207 xEventGroupSetBits(wifi_event, WIFI_ACTION_RX_EVENT);
208 }
209
210 return ESP_OK;
211 }
212
test_wifi_roc(void)213 static void test_wifi_roc(void)
214 {
215 wifi_action_rx_cb_t rx_cb = test_rx_action;
216 char mac_str[19] = {0};
217 EventBits_t bits;
218 uint8_t mac[6];
219
220 test_case_uses_tcpip();
221 start_wifi_as_sta();
222
223 xEventGroupWaitBits(wifi_event, WIFI_START_EVENT, 1, 0, 5000 / portTICK_RATE_MS);
224 TEST_ESP_OK(esp_wifi_get_mac(ESP_IF_WIFI_STA, mac));
225 sprintf(mac_str, MACSTR, MAC2STR(mac));
226 unity_send_signal_param("Listener mac", mac_str);
227
228 TEST_ESP_OK(esp_wifi_remain_on_channel(ESP_IF_WIFI_STA, WIFI_ROC_REQ, TEST_LISTEN_CHANNEL,
229 10000, rx_cb));
230 bits = xEventGroupWaitBits(wifi_event, WIFI_ROC_DONE_EVENT | WIFI_ACTION_RX_EVENT,
231 pdTRUE, pdFALSE, portMAX_DELAY);
232 /* Confirm that Frame has been received successfully */
233 if (bits == WIFI_ACTION_RX_EVENT) {
234 TEST_ESP_OK(esp_wifi_remain_on_channel(ESP_IF_WIFI_STA, WIFI_ROC_CANCEL, 0, 0, NULL));
235 vTaskDelay(1000 / portTICK_PERIOD_MS);
236 stop_wifi();
237 } else {
238 stop_wifi();
239 TEST_FAIL();
240 }
241 }
242
243 TEST_CASE_MULTIPLE_DEVICES("test ROC and Offchannel Action Frame Tx", "[Offchan][test_env=UT_T2_1][timeout=90]", test_wifi_roc, test_wifi_offchan_tx);
244
245 #endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32C3)
246