1 /*
2  * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /*
8  * After station connects to AP and gets IP address by smartconfig,
9  * it will use UDP to send 'ACK' to cellphone.
10  */
11 
12 #include "freertos/FreeRTOS.h"
13 #include "freertos/task.h"
14 #include "esp_netif.h"
15 #include "esp_log.h"
16 #include "esp_wifi.h"
17 #include "esp_event.h"
18 
19 #include <string.h>
20 #include "sys/socket.h"
21 #include "esp_smartconfig.h"
22 #include "smartconfig_ack.h"
23 
24 #define SC_ACK_TASK_PRIORITY             2          /*!< Priority of sending smartconfig ACK task */
25 #define SC_ACK_TASK_STACK_SIZE           2048       /*!< Stack size of sending smartconfig ACK task */
26 
27 #define SC_ACK_TOUCH_DEVICE_PORT         7001       /*!< ESPTouch UDP port of server on device */
28 #define SC_ACK_TOUCH_SERVER_PORT         18266      /*!< ESPTouch UDP port of server on cellphone */
29 #define SC_ACK_TOUCH_V2_SERVER_PORT(i)   (18266+i*10000)     /*!< ESPTouch v2 UDP port of server on cellphone */
30 #define SC_ACK_AIRKISS_SERVER_PORT       10000      /*!< Airkiss UDP port of server on cellphone */
31 #define SC_ACK_AIRKISS_DEVICE_PORT       10001      /*!< Airkiss UDP port of server on device */
32 #define SC_ACK_AIRKISS_TIMEOUT           1500       /*!< Airkiss read data timout millisecond */
33 
34 #define SC_ACK_TOUCH_LEN                 11         /*!< Length of ESPTouch ACK context */
35 #define SC_ACK_AIRKISS_LEN               7          /*!< Length of Airkiss ACK context */
36 
37 #define SC_ACK_MAX_COUNT                 30         /*!< Maximum count of sending smartconfig ACK */
38 
39 /**
40  * @brief Smartconfig parameters passed to sc_ack_send call.
41  */
42 typedef struct sc_ack {
43     smartconfig_type_t type;      /*!< Smartconfig type(ESPTouch or AirKiss) */
44     struct {
45         uint8_t token;            /*!< Smartconfig token from the cellphone */
46         uint8_t mac[6];           /*!< MAC address of station */
47         uint8_t ip[4];            /*!< IP address of cellphone */
48     } ctx;
49 } sc_ack_t;
50 
51 static const char *TAG = "smartconfig";
52 
53 /* Flag to indicate sending smartconfig ACK or not. */
54 static bool s_sc_ack_send = false;
55 
sc_ack_send_get_errno(int fd)56 static int sc_ack_send_get_errno(int fd)
57 {
58     int sock_errno = 0;
59     u32_t optlen = sizeof(sock_errno);
60 
61     if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &sock_errno, &optlen) < 0) {
62         return sock_errno;
63     }
64 
65     return 0;
66 }
67 
sc_ack_send_task(void * pvParameters)68 static void sc_ack_send_task(void *pvParameters)
69 {
70     sc_ack_t *ack = (sc_ack_t *)pvParameters;
71     esp_netif_ip_info_t local_ip;
72     uint8_t remote_ip[4];
73     memcpy(remote_ip, ack->ctx.ip, sizeof(remote_ip));
74     struct sockaddr_in server_addr;
75     socklen_t sin_size = sizeof(server_addr);
76     int send_sock = -1;
77     int optval = 1;
78     int sendlen;
79     int ack_len = (ack->type == SC_TYPE_ESPTOUCH) ? SC_ACK_TOUCH_LEN : SC_ACK_AIRKISS_LEN;
80     uint8_t packet_count = 1;
81     int err;
82     int ret;
83 
84     int remote_port = 0;
85     if (ack->type == SC_TYPE_ESPTOUCH) {
86         remote_port = SC_ACK_TOUCH_SERVER_PORT;
87     } else if (ack->type == SC_TYPE_ESPTOUCH_V2) {
88         uint8_t port_bit =  ack->ctx.token;
89         if(port_bit > 3) {
90             port_bit = 0;
91         }
92         remote_port = SC_ACK_TOUCH_V2_SERVER_PORT(port_bit);
93         memset(remote_ip, 0xFF, sizeof(remote_ip));
94     } else {
95         remote_port = SC_ACK_AIRKISS_SERVER_PORT;
96     }
97 
98     bzero(&server_addr, sizeof(struct sockaddr_in));
99     server_addr.sin_family = AF_INET;
100     memcpy(&server_addr.sin_addr.s_addr, remote_ip, sizeof(remote_ip));
101     server_addr.sin_port = htons(remote_port);
102 
103     esp_wifi_get_mac(WIFI_IF_STA, ack->ctx.mac);
104 
105     vTaskDelay(200 / portTICK_PERIOD_MS);
106 
107     while (s_sc_ack_send) {
108         /* Get local IP address of station */
109         ret = esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &local_ip);
110         if ((ESP_OK == ret) && (local_ip.ip.addr != INADDR_ANY)) {
111             /* If ESPTouch, smartconfig ACK contains local IP address. */
112             if (ack->type == SC_TYPE_ESPTOUCH) {
113                 memcpy(ack->ctx.ip, &local_ip.ip.addr, 4);
114             }
115 
116             /* Create UDP socket. */
117             send_sock = socket(AF_INET, SOCK_DGRAM, 0);
118             if ((send_sock < LWIP_SOCKET_OFFSET) || (send_sock > (FD_SETSIZE - 1))) {
119                 ESP_LOGE(TAG,  "Creat udp socket failed");
120                 goto _end;
121             }
122 
123             if (setsockopt(send_sock, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(int)) < 0) {
124                 ESP_LOGE(TAG,  "setsockopt SO_BROADCAST failed");
125                 goto _end;
126             }
127 
128             if (setsockopt(send_sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int)) < 0) {
129                 ESP_LOGE(TAG,  "setsockopt SO_REUSEADDR failed");
130                 goto _end;
131             }
132 
133             if (ack->type == SC_TYPE_AIRKISS) {
134                 char data = 0;
135                 struct sockaddr_in local_addr, from;
136                 socklen_t sockadd_len = sizeof(struct sockaddr);
137                 struct timeval timeout = {
138                     SC_ACK_AIRKISS_TIMEOUT / 1000,
139                     SC_ACK_AIRKISS_TIMEOUT % 1000 * 1000
140                 };
141 
142                 bzero(&local_addr, sizeof(struct sockaddr_in));
143                 bzero(&from, sizeof(struct sockaddr_in));
144                 local_addr.sin_family = AF_INET;
145                 local_addr.sin_addr.s_addr = INADDR_ANY;
146                 if (ack->type == SC_TYPE_AIRKISS) {
147                     local_addr.sin_port = htons(SC_ACK_AIRKISS_DEVICE_PORT);
148                 } else {
149                     local_addr.sin_port = htons(SC_ACK_TOUCH_DEVICE_PORT);
150                 }
151 
152                 if (bind(send_sock, (struct sockaddr *)&local_addr, sockadd_len) < 0) {
153                     ESP_LOGE(TAG,  "socket bind failed");
154                     goto _end;
155                 }
156                 if (setsockopt(send_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
157                     goto _end;
158                 }
159 
160                 if (recvfrom(send_sock, &data, 1, 0, (struct sockaddr *)&from, &sockadd_len) < 0) {
161                     goto _end;
162                 }
163                 if (from.sin_addr.s_addr != INADDR_ANY) {
164                     memcpy(remote_ip, &from.sin_addr, 4);
165                     server_addr.sin_addr.s_addr = from.sin_addr.s_addr;
166                 } else {
167                     server_addr.sin_addr.s_addr = INADDR_BROADCAST;
168                 }
169             }
170 
171             uint32_t ip_addr = server_addr.sin_addr.s_addr;
172             while (s_sc_ack_send) {
173                 /* Send smartconfig ACK every 100ms. */
174                 vTaskDelay(100 / portTICK_PERIOD_MS);
175 
176                 if (ip_addr != INADDR_BROADCAST) {
177                     sendto(send_sock, &ack->ctx, ack_len, 0, (struct sockaddr*) &server_addr, sin_size);
178                     server_addr.sin_addr.s_addr = INADDR_BROADCAST;
179                     sendlen = sendto(send_sock, &ack->ctx, ack_len, 0, (struct sockaddr*) &server_addr, sin_size);
180                     server_addr.sin_addr.s_addr = ip_addr;
181                 } else {
182                     sendlen = sendto(send_sock, &ack->ctx, ack_len, 0, (struct sockaddr*) &server_addr, sin_size);
183                 }
184 
185                 if (sendlen <= 0) {
186                     err = sc_ack_send_get_errno(send_sock);
187                     ESP_LOGD(TAG, "send failed, errno %d", err);
188                     vTaskDelay(100 / portTICK_PERIOD_MS);
189                 }
190 
191                 /*  Send 30 smartconfig ACKs. Then smartconfig is successful. */
192                 if (packet_count++ >= SC_ACK_MAX_COUNT) {
193                     esp_event_post(SC_EVENT, SC_EVENT_SEND_ACK_DONE, NULL, 0, portMAX_DELAY);
194                     goto _end;
195                 }
196             }
197         }
198         else {
199             vTaskDelay((TickType_t)(100 / portTICK_PERIOD_MS));
200         }
201     }
202 
203 _end:
204     close(send_sock);
205     free(ack);
206     vTaskDelete(NULL);
207 }
208 
sc_send_ack_start(smartconfig_type_t type,uint8_t token,uint8_t * cellphone_ip)209 esp_err_t sc_send_ack_start(smartconfig_type_t type, uint8_t token, uint8_t *cellphone_ip)
210 {
211     sc_ack_t *ack = NULL;
212 
213     if (cellphone_ip == NULL) {
214         ESP_LOGE(TAG, "Cellphone IP address is NULL");
215         return ESP_ERR_INVALID_ARG;
216     }
217 
218     ack = malloc(sizeof(sc_ack_t));
219     if (ack == NULL) {
220         ESP_LOGE(TAG, "ACK parameter malloc fail");
221         return ESP_ERR_NO_MEM;
222     }
223     ack->type = type;
224     ack->ctx.token = token;
225     memcpy(ack->ctx.ip, cellphone_ip, 4);
226 
227     s_sc_ack_send = true;
228 
229     if (xTaskCreate(sc_ack_send_task, "sc_ack_send_task", SC_ACK_TASK_STACK_SIZE, ack, SC_ACK_TASK_PRIORITY, NULL) != pdPASS) {
230         ESP_LOGE(TAG, "Create sending smartconfig ACK task fail");
231         free(ack);
232         return ESP_ERR_NO_MEM;
233     }
234 
235     return ESP_OK;
236 }
237 
sc_send_ack_stop(void)238 void sc_send_ack_stop(void)
239 {
240     s_sc_ack_send = false;
241 }
242