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