1 // Copyright 2019 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 
16 
17 #include "esp_netif.h"
18 #include "esp_log.h"
19 #include "esp_netif_slip.h"
20 #include "esp_netif_lwip_internal.h"
21 #include "esp_netif_net_stack.h"
22 
23 #ifdef CONFIG_ESP_NETIF_TCPIP_LWIP
24 
25 #include "lwip/dns.h"
26 #include "lwip/opt.h"
27 #include "lwip/ip6_addr.h"
28 #include "lwip/netif.h"
29 #include "netif/slipif.h"
30 #include "lwip/sio.h"
31 
32 #include <string.h>
33 
34 static const char *TAG = "esp-netif_lwip-slip";
35 
36 /**
37  * @brief LWIP SLIP context object extends esp-netif related data
38  */
39 typedef struct lwip_slip_ctx {
40     //! Generic esp-netif related data
41     netif_related_data_t base;
42 
43     //! SLIP interface IP6 address
44     esp_ip6_addr_t addr;
45 
46 } lwip_slip_ctx_t;
47 
48 /**
49  * @brief Create a new lwip slip interface
50  */
esp_netif_new_slip(esp_netif_t * esp_netif,const esp_netif_netstack_config_t * esp_netif_stack_config)51 netif_related_data_t * esp_netif_new_slip(esp_netif_t *esp_netif, const esp_netif_netstack_config_t *esp_netif_stack_config)
52 {
53     ESP_LOGD(TAG, "%s", __func__);
54 
55     // Fetch netif and create context
56     struct netif *netif_impl = esp_netif->lwip_netif;
57 
58     lwip_slip_ctx_t *slip_ctx = calloc(1, sizeof(lwip_slip_ctx_t));
59     if (slip_ctx == NULL) {
60         ESP_LOGE(TAG, "%s: cannot allocate lwip_slip_ctx_t", __func__);
61         return NULL;
62     }
63     // Setup the generic esp-netif fields
64     slip_ctx->base.is_point2point = true;
65     slip_ctx->base.netif_type = SLIP_LWIP_NETIF;
66 
67     ESP_LOGD(TAG, "%s: Initialising SLIP (esp_netif %p, lwip_netif %p)", __func__, esp_netif, netif_impl);
68 
69     ESP_LOGI(TAG, "%s: Created SLIP interface (netif %p, slip_ctx: %p)", __func__, esp_netif, slip_ctx);
70 
71     return (netif_related_data_t *)slip_ctx;
72 }
73 
74 /**
75  * @brief Stops the SLIP interface
76  */
esp_netif_stop_slip(esp_netif_t * esp_netif)77 esp_err_t esp_netif_stop_slip(esp_netif_t *esp_netif)
78 {
79     lwip_slip_ctx_t *slip_ctx = (lwip_slip_ctx_t *)esp_netif->related_data;
80     assert(slip_ctx->base.netif_type == SLIP_LWIP_NETIF);
81 
82     ESP_LOGI(TAG, "%s: Stopped SLIP connection: %p", __func__, slip_ctx);
83 
84     // Stop interface
85     netif_set_link_down(esp_netif->lwip_netif);
86 
87     return ESP_OK;
88 }
89 
90 /**
91  * @brief Starts the SLIP interface
92  */
esp_netif_start_slip(esp_netif_t * esp_netif)93 esp_err_t esp_netif_start_slip(esp_netif_t *esp_netif)
94 {
95     lwip_slip_ctx_t *slip_ctx = (lwip_slip_ctx_t *)esp_netif->related_data;
96     assert(slip_ctx->base.netif_type == SLIP_LWIP_NETIF);
97 
98     ESP_LOGI(TAG, "%s: Starting SLIP interface: %p", __func__, slip_ctx);
99 
100     // Set the netif up
101     netif_set_up(esp_netif->lwip_netif);
102     netif_set_link_up(esp_netif->lwip_netif);
103 #if CONFIG_LWIP_IPV6
104     int8_t addr_index = 0;
105 
106     netif_ip6_addr_set(esp_netif->lwip_netif, addr_index, (ip6_addr_t *)&slip_ctx->addr);
107     netif_ip6_addr_set_state(esp_netif->lwip_netif, addr_index, IP6_ADDR_VALID);
108 #endif
109     return ESP_OK;
110 }
111 
112 
113 /**
114  * @brief Sets paramaters for the supplied netif
115  */
esp_netif_slip_set_params(esp_netif_t * netif,const esp_netif_slip_config_t * slip_config)116 esp_err_t esp_netif_slip_set_params(esp_netif_t *netif, const esp_netif_slip_config_t *slip_config)
117 {
118 
119     lwip_slip_ctx_t *slip_ctx = (lwip_slip_ctx_t *)netif->related_data;
120     assert(slip_ctx->base.netif_type == SLIP_LWIP_NETIF);
121 
122     ESP_LOGD(TAG, "%s (slip_ctx: %p)", __func__, slip_ctx);
123 
124     if (netif_is_link_up(netif->lwip_netif)) {
125         ESP_LOGE(TAG, "Cannot set parameters while SLIP interface is running");
126         return ESP_ERR_INVALID_STATE;
127     }
128 
129     memcpy(&slip_ctx->addr, &slip_config->ip6_addr, sizeof(esp_ip6_addr_t));
130 
131 
132     return ESP_OK;
133 }
134 
135 #if CONFIG_LWIP_IPV6
esp_netif_slip_set_ipv6(esp_netif_t * netif,const esp_ip6_addr_t * ipv6)136 esp_err_t esp_netif_slip_set_ipv6(esp_netif_t *netif, const esp_ip6_addr_t *ipv6)
137 {
138     lwip_slip_ctx_t *slip_ctx = (lwip_slip_ctx_t *)netif->related_data;
139     assert(slip_ctx->base.netif_type == SLIP_LWIP_NETIF);
140 
141     ESP_LOGV(TAG, "%s (slip_ctx: %p)", __func__, slip_ctx);
142 
143     if (netif_is_link_up(netif->lwip_netif)) {
144         ESP_LOGE(TAG, "Cannot set parameters while SLIP interface is running");
145         return ESP_ERR_INVALID_STATE;
146     }
147     memcpy(&slip_ctx->addr, ipv6, sizeof(ip6_addr_t));
148     int8_t addr_index = 0;
149 
150     netif_ip6_addr_set(netif->lwip_netif, addr_index, (ip6_addr_t *)&slip_ctx->addr);
151     netif_ip6_addr_set_state(netif->lwip_netif, addr_index, IP6_ADDR_VALID);
152 
153     return ESP_OK;
154 }
155 #endif
156 
157 /**
158  * @brief Write incoming serial data to the SLIP interface
159  */
esp_netif_lwip_slip_input(void * h,void * buffer,unsigned int len,void * eb)160 void esp_netif_lwip_slip_input(void *h, void *buffer, unsigned int len, void *eb)
161 {
162     esp_netif_t *netif = h;
163     lwip_slip_ctx_t *slip_ctx = (lwip_slip_ctx_t *)netif->related_data;
164     assert(slip_ctx->base.netif_type == SLIP_LWIP_NETIF);
165 
166     ESP_LOGD(TAG, "%s", __func__);
167     ESP_LOG_BUFFER_HEXDUMP(TAG, buffer, len, ESP_LOG_DEBUG);
168 
169     // Update slip netif with data
170     const int max_batch = 255;
171     int sent = 0;
172     while(sent < len) {
173         int batch = (len - sent) > max_batch ? max_batch : (len - sent);
174         slipif_received_bytes(netif->lwip_netif, buffer+sent, batch);
175         sent += batch;
176     }
177 
178     // Process incoming bytes
179     for (int i = 0; i < len; i++) {
180         slipif_process_rxqueue(netif->lwip_netif);
181     }
182 }
183 
184 /**
185  * @brief Write raw data out the SLIP interface
186  */
esp_netif_lwip_slip_raw_output(esp_netif_t * slip_netif,void * buffer,size_t len)187 void esp_netif_lwip_slip_raw_output(esp_netif_t *slip_netif, void *buffer, size_t len)
188 {
189     struct netif *lwip_netif = slip_netif->lwip_netif;
190 
191     ESP_LOGD(TAG, "%s", __func__);
192 
193     struct pbuf p = {
194         .next = NULL,
195         .payload = buffer,
196         .tot_len = len,
197         .len = len,
198     };
199 
200     // Call slip if output function to feed data out slip interface
201 #if CONFIG_LWIP_IPV6
202     lwip_netif->output_ip6(lwip_netif, &p, NULL);
203 #else
204     lwip_netif->output(lwip_netif, &p, NULL);
205 #endif
206 }
207 
208 /**
209  * @brief Destroys the SLIP context object
210  */
esp_netif_destroy_slip(netif_related_data_t * slip)211 void esp_netif_destroy_slip(netif_related_data_t *slip)
212 {
213     ESP_LOGD(TAG, "%s", __func__);
214 
215     // Free base object
216     free(slip);
217 }
218 
esp_slip_get_ip6(esp_netif_t * slip_netif)219 const esp_ip6_addr_t *esp_slip_get_ip6(esp_netif_t *slip_netif)
220 {
221     lwip_slip_ctx_t *slip_ctx = (lwip_slip_ctx_t *)slip_netif->related_data;
222     assert(slip_ctx->base.netif_type == SLIP_LWIP_NETIF);
223     return &slip_ctx->addr;
224 }
225 
226 /** @brief Get esp-netif object corresponding to registration index
227  */
get_netif_with_esp_index(int index)228 static esp_netif_t * get_netif_with_esp_index(int index)
229 {
230     esp_netif_t *netif = NULL;
231     int counter = 0;
232     while ((netif = esp_netif_next(netif)) != NULL) {
233         if (counter == index) {
234             return netif;
235         }
236         counter++;
237     }
238     return NULL;
239 }
240 
241 /** @brief Return list registration index of the supplied netif ptr
242  */
get_esp_netif_index(esp_netif_t * esp_netif)243 static int get_esp_netif_index(esp_netif_t * esp_netif)
244 {
245     esp_netif_t *netif = NULL;
246     int counter = 0;
247     while ((netif = esp_netif_next(netif)) != NULL) {
248         if (esp_netif == netif) {
249             return counter;
250         }
251         counter++;
252     }
253     return -1;
254 }
255 
esp_slipif_init(struct netif * netif)256 err_t esp_slipif_init(struct netif *netif)
257 {
258     esp_netif_t *esp_netif = netif->state;
259     int esp_index = get_esp_netif_index(esp_netif);
260     if (esp_index < 0) {
261         return ERR_IF;
262     }
263 
264     // Store netif index in net interface for SIO open command to abstract the dev
265     netif->state = (void *)esp_index;
266 
267     return slipif_init(netif);
268 }
269 
270 static const struct esp_netif_netstack_config s_netif_config_slip = {
271         .lwip = {
272                 .init_fn = esp_slipif_init,
273                 .input_fn = esp_netif_lwip_slip_input,
274         }
275 };
276 
277 const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_slip = &s_netif_config_slip;
278 
279 
280 /***
281  * @brief Open a serial device for communication
282  */
sio_open(uint8_t devnum)283 sio_fd_t sio_open(uint8_t devnum)
284 {
285     ESP_LOGD(TAG, "Opening device: %d\r\n", devnum);
286 
287     esp_netif_t *esp_netif = get_netif_with_esp_index(devnum);
288     if (!esp_netif) {
289         ESP_LOGE(TAG, "didn't find esp-netif with index=%d\n", devnum);
290         return NULL;
291     }
292 
293     // Return SIO handle
294     return esp_netif;
295 }
296 
297 /***
298  * @brief Send a single character to the serial device (blocking)
299  */
sio_send(uint8_t c,sio_fd_t fd)300 void sio_send(uint8_t c, sio_fd_t fd)
301 {
302     esp_netif_t *esp_netif = fd;
303 
304     ESP_LOGD(TAG, "%s", __func__);
305     ESP_LOG_BUFFER_HEX_LEVEL(TAG, &c, 1, ESP_LOG_DEBUG);
306 
307     esp_err_t ret = esp_netif_transmit(esp_netif, &c, 1);
308     if (ret != ESP_OK) {
309         // Handle errors
310         ESP_LOGD(TAG, "%s: uart_write_bytes error %i", __func__, ret);
311     }
312 }
313 
314 #endif /* CONFIG_ESP_NETIF_TCPIP_LWIP */
315