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 #include "esp_netif.h"
17
18 #ifdef CONFIG_ESP_NETIF_TCPIP_LWIP
19
20 #include "lwip/dns.h"
21 #include "netif/ppp/pppapi.h"
22 #include "netif/ppp/pppos.h"
23 #include "esp_log.h"
24 #include "esp_netif_net_stack.h"
25 #include "esp_event.h"
26 #include "esp_netif_ppp.h"
27 #include "esp_netif_lwip_internal.h"
28 #include <string.h>
29 #include "lwip/ip6_addr.h"
30
31 ESP_EVENT_DEFINE_BASE(NETIF_PPP_STATUS);
32
33 static const char *TAG = "esp-netif_lwip-ppp";
34
35 /**
36 * @brief internal lwip_ppp context struct extends the netif related data
37 * used to hold PPP netif related parameters
38 */
39 typedef struct lwip_peer2peer_ctx {
40 netif_related_data_t base; // Generic portion of netif-related data
41 // PPP specific fields follow
42 bool ppp_phase_event_enabled;
43 bool ppp_error_event_enabled;
44 ppp_pcb *ppp;
45 } lwip_peer2peer_ctx_t;
46
47 /**
48 * @brief lwip callback from PPP client used here to produce PPP error related events,
49 * as well as some IP events
50 */
on_ppp_status_changed(ppp_pcb * pcb,int err_code,void * ctx)51 static void on_ppp_status_changed(ppp_pcb *pcb, int err_code, void *ctx)
52 {
53 struct netif *pppif = ppp_netif(pcb);
54 const ip_addr_t *dest_ip = NULL;
55 esp_netif_t *netif = ctx;
56 ip_event_got_ip_t evt = {
57 .esp_netif = netif,
58 .if_index = -1,
59 };
60 esp_err_t err;
61 struct lwip_peer2peer_ctx *obj = (struct lwip_peer2peer_ctx*)netif->related_data;
62 assert(obj->base.netif_type == PPP_LWIP_NETIF);
63 esp_ip4_addr_t ns1;
64 esp_ip4_addr_t ns2;
65 switch (err_code) {
66 case PPPERR_NONE: /* Connected */
67 ESP_LOGI(TAG, "Connected");
68 if (pcb->if4_up && !ip_addr_isany(&pppif->ip_addr)) {
69 esp_netif_ip_info_t *ip_info = netif->ip_info;
70 ip4_addr_set(&ip_info->ip, ip_2_ip4(&pppif->ip_addr));
71 ip4_addr_set(&ip_info->netmask, ip_2_ip4(&pppif->netmask));
72 ip4_addr_set(&ip_info->gw, ip_2_ip4(&pppif->gw));
73
74 ip4_addr_set(&evt.ip_info.ip, ip_2_ip4(&pppif->ip_addr));
75 ip4_addr_set(&evt.ip_info.gw, ip_2_ip4(&pppif->gw));
76 ip4_addr_set(&evt.ip_info.netmask, ip_2_ip4(&pppif->netmask));
77
78 dest_ip = dns_getserver(0);
79 if(dest_ip != NULL){
80 ip4_addr_set(&ns1, ip_2_ip4(dest_ip));
81 }
82 dest_ip = dns_getserver(1);
83 if(dest_ip != NULL){
84 ip4_addr_set(&ns2, ip_2_ip4(dest_ip));
85 }
86 ESP_LOGI(TAG, "Name Server1: " IPSTR, IP2STR(&ns1));
87 ESP_LOGI(TAG, "Name Server2: " IPSTR, IP2STR(&ns2));
88
89
90 err = esp_event_post(IP_EVENT, netif->get_ip_event, &evt, sizeof(evt), 0);
91 if (ESP_OK != err) {
92 ESP_LOGE(TAG, "esp_event_post failed with code %d", err);
93 }
94 return;
95 #if PPP_IPV6_SUPPORT
96 } else if (pcb->if6_up && !ip_addr_isany(&pppif->ip6_addr[0])) {
97 esp_netif_ip6_info_t ip6_info;
98 ip6_addr_t lwip_ip6_info;
99 ip_event_got_ip6_t ip6_event = { .esp_netif = pppif->state, .if_index = -1 };
100
101 ip6_addr_set(&lwip_ip6_info, ip_2_ip6(&pppif->ip6_addr[0]));
102 #if LWIP_IPV6_SCOPES
103 memcpy(&ip6_info.ip, &lwip_ip6_info, sizeof(esp_ip6_addr_t));
104 #else
105 memcpy(&ip6_info.ip, &lwip_ip6_info, sizeof(ip6_addr_t));
106 ip6_info.ip.zone = 0; // zero out zone, as not used in lwip
107 #endif /* LWIP_IPV6_SCOPES */
108 memcpy(&ip6_event.ip6_info, &ip6_info, sizeof(esp_netif_ip6_info_t));
109
110 ESP_LOGI(TAG, "Got IPv6 address " IPV6STR, IPV62STR(pppif->ip6_addr[0].u_addr.ip6));
111 err = esp_event_post(IP_EVENT, IP_EVENT_GOT_IP6, &ip6_event, sizeof(ip6_event), 0);
112 if (ESP_OK != err) {
113 ESP_LOGE(TAG, "esp_event_post failed with code %d", err);
114 }
115 return;
116 #endif /* PPP_IPV6_SUPPORT */
117 } else {
118 ESP_LOGE(TAG, "Unexpected connected event");
119 return;
120 }
121
122 case PPPERR_PARAM:
123 ESP_LOGE(TAG, "Invalid parameter");
124 break;
125 case PPPERR_OPEN:
126 ESP_LOGE(TAG, "Unable to open PPP session");
127 break;
128 case PPPERR_DEVICE:
129 ESP_LOGE(TAG, "Invalid I/O device for PPP");
130 break;
131 case PPPERR_ALLOC:
132 ESP_LOGE(TAG, "Unable to allocate resources");
133 break;
134 case PPPERR_USER: /* User interrupt */
135 ESP_LOGI(TAG, "User interrupt");
136 break;
137 case PPPERR_CONNECT: /* Connection lost */
138 ESP_LOGI(TAG, "Connection lost");
139 err = esp_event_post(IP_EVENT, netif->lost_ip_event, &evt, sizeof(evt), 0);
140
141 if (ESP_OK != err) {
142 ESP_LOGE(TAG, "esp_event_send_internal failed with code %d", err);
143 }
144 return;
145
146 case PPPERR_AUTHFAIL:
147 ESP_LOGE(TAG, "Failed authentication challenge");
148 break;
149 case PPPERR_PROTOCOL:
150 ESP_LOGE(TAG, "Failed to meet protocol");
151 break;
152 case PPPERR_PEERDEAD:
153 ESP_LOGE(TAG, "Connection timeout");
154 break;
155 case PPPERR_IDLETIMEOUT:
156 ESP_LOGE(TAG, "Idle Timeout");
157 break;
158 case PPPERR_CONNECTTIME:
159 ESP_LOGE(TAG, "Max connect time reached");
160 break;
161 case PPPERR_LOOPBACK:
162 ESP_LOGE(TAG, "Loopback detected");
163 break;
164 default:
165 ESP_LOGE(TAG, "Unknown error code %d", err_code);
166 break;
167 }
168 if (obj->ppp_error_event_enabled) {
169 err = esp_event_post(NETIF_PPP_STATUS, err_code, &netif, sizeof(netif), 0);
170 if (err != ESP_OK) {
171 ESP_LOGE(TAG, "esp_event_post failed with code %d", err);
172 }
173
174 }
175 }
176
177 #if PPP_NOTIFY_PHASE
178 /**
179 * @brief Notify phase callback which is called on each PPP internal state change
180 *
181 * @param pcb PPP control block
182 * @param phase Phase ID
183 * @param ctx Context of callback
184 */
on_ppp_notify_phase(ppp_pcb * pcb,u8_t phase,void * ctx)185 static void on_ppp_notify_phase(ppp_pcb *pcb, u8_t phase, void *ctx)
186 {
187 switch (phase) {
188 case PPP_PHASE_DEAD:
189 ESP_LOGD(TAG, "Phase Dead");
190 break;
191 case PPP_PHASE_INITIALIZE:
192 ESP_LOGD(TAG, "Phase Start");
193 break;
194 case PPP_PHASE_ESTABLISH:
195 ESP_LOGD(TAG, "Phase Establish");
196 break;
197 case PPP_PHASE_AUTHENTICATE:
198 ESP_LOGD(TAG, "Phase Authenticate");
199 break;
200 case PPP_PHASE_NETWORK:
201 ESP_LOGD(TAG, "Phase Network");
202 break;
203 case PPP_PHASE_RUNNING:
204 ESP_LOGD(TAG, "Phase Running");
205 break;
206 case PPP_PHASE_TERMINATE:
207 ESP_LOGD(TAG, "Phase Terminate");
208 break;
209 case PPP_PHASE_DISCONNECT:
210 ESP_LOGD(TAG, "Phase Disconnect");
211 break;
212 default:
213 ESP_LOGW(TAG, "Phase Unknown: %d", phase);
214 break;
215 }
216 esp_netif_t *netif = ctx;
217 lwip_peer2peer_ctx_t *obj = (lwip_peer2peer_ctx_t *)netif->related_data;
218 assert(obj->base.netif_type == PPP_LWIP_NETIF);
219 if (obj && obj->ppp_phase_event_enabled) {
220 esp_err_t err = esp_event_post(NETIF_PPP_STATUS, NETIF_PP_PHASE_OFFSET + phase, &netif, sizeof(netif), 0);
221 if (err != ESP_OK) {
222 ESP_LOGE(TAG, "esp_event_post failed with code %d", err);
223 }
224 }
225 }
226 #endif // PPP_NOTIFY_PHASE
227
228 /**
229 * @brief PPP low level output callback used to transmit data using standard esp-netif interafce
230 *
231 * @param pcb PPP control block
232 * @param data Buffer to write to serial port
233 * @param len Length of the data buffer
234 * @param ctx Context of callback
235 *
236 * @return uint32_t Length of data successfully sent
237 */
pppos_low_level_output(ppp_pcb * pcb,uint8_t * data,uint32_t len,void * netif)238 static uint32_t pppos_low_level_output(ppp_pcb *pcb, uint8_t *data, uint32_t len, void *netif)
239 {
240 esp_err_t ret = esp_netif_transmit(netif, data, len);
241 if (ret == ESP_OK) {
242 return len;
243 }
244 return 0;
245 }
246
esp_netif_ppp_set_auth(esp_netif_t * netif,esp_netif_auth_type_t authtype,const char * user,const char * passwd)247 esp_err_t esp_netif_ppp_set_auth(esp_netif_t *netif, esp_netif_auth_type_t authtype, const char *user, const char *passwd)
248 {
249 if (!_IS_NETIF_POINT2POINT_TYPE(netif, PPP_LWIP_NETIF)) {
250 return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
251 }
252 #if PPP_AUTH_SUPPORT
253 lwip_peer2peer_ctx_t *ppp_ctx = (lwip_peer2peer_ctx_t *)netif->related_data;
254 assert(ppp_ctx->base.netif_type == PPP_LWIP_NETIF);
255 pppapi_set_auth(ppp_ctx->ppp, authtype, user, passwd);
256 return ESP_OK;
257 #else
258 ESP_LOGE(TAG, "%s failed: No authorisation enabled in menuconfig", __func__);
259 return ESP_ERR_ESP_NETIF_IF_NOT_READY;
260 #endif
261 }
262
esp_netif_ppp_set_default_netif(netif_related_data_t * netif_related)263 void esp_netif_ppp_set_default_netif(netif_related_data_t *netif_related)
264 {
265 lwip_peer2peer_ctx_t *ppp_ctx = (lwip_peer2peer_ctx_t *)netif_related;
266 assert(ppp_ctx->base.netif_type == PPP_LWIP_NETIF);
267
268 ppp_set_default(ppp_ctx->ppp);
269 }
270
esp_netif_new_ppp(esp_netif_t * esp_netif,const esp_netif_netstack_config_t * esp_netif_stack_config)271 netif_related_data_t * esp_netif_new_ppp(esp_netif_t *esp_netif, const esp_netif_netstack_config_t *esp_netif_stack_config)
272 {
273 struct netif * netif_impl = esp_netif->lwip_netif;
274 struct lwip_peer2peer_ctx * ppp_obj = calloc(1, sizeof(struct lwip_peer2peer_ctx));
275 if (ppp_obj == NULL) {
276 ESP_LOGE(TAG, "%s: cannot allocate lwip_ppp_ctx", __func__);
277 return NULL;
278 }
279 // Setup the generic esp-netif fields
280 ppp_obj->base.is_point2point = true;
281 ppp_obj->base.netif_type = PPP_LWIP_NETIF;
282
283 ppp_obj->ppp = pppapi_pppos_create(netif_impl, pppos_low_level_output, on_ppp_status_changed, esp_netif);
284 ESP_LOGD(TAG, "%s: PPP connection created: %p", __func__, ppp_obj->ppp);
285 if (!ppp_obj->ppp) {
286 ESP_LOGE(TAG, "%s: lwIP PPP connection cannot be created", __func__);
287 }
288
289 // Set the related data here, since the phase callback could be triggered before this function exits
290 esp_netif->related_data = (netif_related_data_t *)ppp_obj;
291 #if PPP_NOTIFY_PHASE
292 ppp_set_notify_phase_callback(ppp_obj->ppp, on_ppp_notify_phase);
293 #endif
294 ppp_set_usepeerdns(ppp_obj->ppp, 1);
295
296 return (netif_related_data_t *)ppp_obj;
297 }
298
esp_netif_start_ppp(esp_netif_t * esp_netif)299 esp_err_t esp_netif_start_ppp(esp_netif_t *esp_netif)
300 {
301 netif_related_data_t *netif_related = esp_netif->related_data;
302 lwip_peer2peer_ctx_t *ppp_ctx = (lwip_peer2peer_ctx_t *)netif_related;
303 assert(ppp_ctx->base.netif_type == PPP_LWIP_NETIF);
304
305 ESP_LOGD(TAG, "%s: Starting PPP connection: %p", __func__, ppp_ctx->ppp);
306 esp_err_t err = pppapi_connect(ppp_ctx->ppp, 0);
307 if (err != ESP_OK) {
308 ESP_LOGE(TAG, "%s: PPP connection cannot be started", __func__);
309 if (ppp_ctx->ppp_error_event_enabled) {
310 esp_event_post(NETIF_PPP_STATUS, NETIF_PPP_CONNECT_FAILED, esp_netif, sizeof(esp_netif), 0);
311 }
312 return ESP_FAIL;
313 }
314 return ESP_OK;
315 }
316
esp_netif_lwip_ppp_input(void * ppp_ctx,void * buffer,size_t len,void * eb)317 void esp_netif_lwip_ppp_input(void *ppp_ctx, void *buffer, size_t len, void *eb)
318 {
319 struct lwip_peer2peer_ctx * obj = ppp_ctx;
320 err_t ret = pppos_input_tcpip(obj->ppp, buffer, len);
321 if (ret != ERR_OK) {
322 ESP_LOGE(TAG, "pppos_input_tcpip failed with %d", ret);
323 }
324 }
325
esp_netif_stop_ppp(netif_related_data_t * netif_related)326 esp_err_t esp_netif_stop_ppp(netif_related_data_t *netif_related)
327 {
328 lwip_peer2peer_ctx_t *ppp_ctx = (lwip_peer2peer_ctx_t *)netif_related;
329 assert(ppp_ctx->base.netif_type == PPP_LWIP_NETIF);
330 ESP_LOGD(TAG, "%s: Stopped PPP connection: %p", __func__, ppp_ctx->ppp);
331 err_t ret = pppapi_close(ppp_ctx->ppp, 0);
332 if (ret != ERR_OK) {
333 ESP_LOGE(TAG, "pppapi_close failed with %d", ret);
334 return ESP_FAIL;
335 }
336 return ESP_OK;
337 }
338
esp_netif_destroy_ppp(netif_related_data_t * netif_related)339 void esp_netif_destroy_ppp(netif_related_data_t *netif_related)
340 {
341 lwip_peer2peer_ctx_t *ppp_ctx = (lwip_peer2peer_ctx_t *)netif_related;
342 assert(ppp_ctx->base.netif_type == PPP_LWIP_NETIF);
343
344 pppapi_free(ppp_ctx->ppp);
345 free(netif_related);
346 }
347
esp_netif_ppp_set_params(esp_netif_t * netif,const esp_netif_ppp_config_t * config)348 esp_err_t esp_netif_ppp_set_params(esp_netif_t *netif, const esp_netif_ppp_config_t *config)
349 {
350 if (netif == NULL || netif->related_data == NULL || config == NULL ||
351 ((struct lwip_peer2peer_ctx *)netif->related_data)->base.netif_type != PPP_LWIP_NETIF) {
352 return ESP_ERR_INVALID_ARG;
353 }
354 struct lwip_peer2peer_ctx *obj = (struct lwip_peer2peer_ctx *)netif->related_data;
355 obj->ppp_phase_event_enabled = config->ppp_phase_event_enabled;
356 obj->ppp_error_event_enabled = config->ppp_error_event_enabled;
357 return ESP_OK;
358 }
359
esp_netif_ppp_get_params(esp_netif_t * netif,esp_netif_ppp_config_t * config)360 esp_err_t esp_netif_ppp_get_params(esp_netif_t *netif, esp_netif_ppp_config_t *config)
361 {
362 if (netif == NULL || netif->related_data == NULL || config == NULL ||
363 ((struct lwip_peer2peer_ctx *)netif->related_data)->base.netif_type != PPP_LWIP_NETIF) {
364 return ESP_ERR_INVALID_ARG;
365 }
366 struct lwip_peer2peer_ctx *obj = (struct lwip_peer2peer_ctx *)netif->related_data;
367 config->ppp_phase_event_enabled = obj->ppp_phase_event_enabled;
368 config->ppp_error_event_enabled = obj->ppp_error_event_enabled;
369 return ESP_OK;
370 }
371
372 #endif /* CONFIG_ESP_NETIF_TCPIP_LWIP */
373