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