1 /*
2 * Copyright (c) 2019 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(net_l2_ppp, CONFIG_NET_L2_PPP_LOG_LEVEL);
9
10 #include <stdlib.h>
11 #include <zephyr/net/ethernet.h>
12 #include <zephyr/net/net_core.h>
13 #include <zephyr/net/net_l2.h>
14 #include <zephyr/net/net_if.h>
15 #include <zephyr/net/net_pkt.h>
16 #include <zephyr/net/net_mgmt.h>
17 #include <zephyr/net/ppp.h>
18 #include <zephyr/sys/iterable_sections.h>
19
20 #include "net_private.h"
21
22 #include "ppp_stats.h"
23 #include "ppp_internal.h"
24
25 static K_FIFO_DEFINE(tx_queue);
26
27 #if defined(CONFIG_NET_TC_THREAD_COOPERATIVE)
28 /* Lowest priority cooperative thread */
29 #define THREAD_PRIORITY K_PRIO_COOP(CONFIG_NET_L2_PPP_THREAD_PRIO)
30 #else
31 #define THREAD_PRIORITY K_PRIO_PREEMPT(CONFIG_NET_L2_PPP_THREAD_PRIO)
32 #endif
33
34 static void tx_handler(void *p1, void *p2, void *p3);
35
36 static K_THREAD_DEFINE(tx_handler_thread, CONFIG_NET_L2_PPP_TX_STACK_SIZE,
37 tx_handler, NULL, NULL, NULL,
38 THREAD_PRIORITY, 0, 0);
39
40 static const struct ppp_protocol_handler *ppp_lcp;
41
ppp_update_rx_stats(struct net_if * iface,struct net_pkt * pkt,size_t length)42 static void ppp_update_rx_stats(struct net_if *iface,
43 struct net_pkt *pkt, size_t length)
44 {
45 #if defined(CONFIG_NET_STATISTICS_PPP)
46 ppp_stats_update_bytes_rx(iface, length);
47 ppp_stats_update_pkts_rx(iface);
48 #endif /* CONFIG_NET_STATISTICS_PPP */
49 }
50
ppp_update_tx_stats(struct net_if * iface,struct net_pkt * pkt,size_t length)51 static void ppp_update_tx_stats(struct net_if *iface,
52 struct net_pkt *pkt, size_t length)
53 {
54 #if defined(CONFIG_NET_STATISTICS_PPP)
55 ppp_stats_update_bytes_tx(iface, length);
56 ppp_stats_update_pkts_tx(iface);
57 #endif /* CONFIG_NET_STATISTICS_PPP */
58 }
59
60 #if defined(CONFIG_NET_TEST)
61 typedef enum net_verdict (*ppp_l2_callback_t)(struct net_if *iface,
62 struct net_pkt *pkt);
63
64 static ppp_l2_callback_t testing_cb;
65
ppp_l2_register_pkt_cb(ppp_l2_callback_t cb)66 void ppp_l2_register_pkt_cb(ppp_l2_callback_t cb)
67 {
68 testing_cb = cb;
69 }
70 #endif
71
process_ppp_msg(struct net_if * iface,struct net_pkt * pkt)72 static enum net_verdict process_ppp_msg(struct net_if *iface,
73 struct net_pkt *pkt)
74 {
75 struct ppp_context *ctx = net_if_l2_data(iface);
76 enum net_verdict verdict = NET_DROP;
77 uint16_t protocol;
78 int ret;
79
80 if (!ctx->is_ready_to_serve) {
81 goto quit;
82 }
83
84 ret = net_pkt_read_be16(pkt, &protocol);
85 if (ret < 0) {
86 goto quit;
87 }
88
89 if ((IS_ENABLED(CONFIG_NET_IPV4) && protocol == PPP_IP) ||
90 (IS_ENABLED(CONFIG_NET_IPV6) && protocol == PPP_IPV6)) {
91 /* Remove the protocol field so that IP packet processing
92 * continues properly in net_core.c:process_data()
93 */
94 (void)net_buf_pull_be16(pkt->buffer);
95 net_pkt_cursor_init(pkt);
96 return NET_CONTINUE;
97 }
98
99 STRUCT_SECTION_FOREACH(ppp_protocol_handler, proto) {
100 if (proto->protocol != protocol) {
101 continue;
102 }
103
104 return proto->handler(ctx, iface, pkt);
105 }
106
107 switch (protocol) {
108 case PPP_IP:
109 case PPP_IPV6:
110 case PPP_ECP:
111 case PPP_CCP:
112 case PPP_LCP:
113 case PPP_IPCP:
114 case PPP_IPV6CP:
115 ppp_send_proto_rej(iface, pkt, protocol);
116 break;
117 default:
118 break;
119 }
120
121 NET_DBG("%s protocol %s%s(0x%02x)",
122 ppp_proto2str(protocol) ? "Unhandled" : "Unknown",
123 ppp_proto2str(protocol),
124 ppp_proto2str(protocol) ? " " : "",
125 protocol);
126
127 quit:
128 return verdict;
129 }
130
ppp_recv(struct net_if * iface,struct net_pkt * pkt)131 static enum net_verdict ppp_recv(struct net_if *iface,
132 struct net_pkt *pkt)
133 {
134 enum net_verdict verdict;
135
136 #if defined(CONFIG_NET_TEST)
137 /* If we are running a PPP unit test, then feed the packet
138 * back to test app for verification.
139 */
140 if (testing_cb) {
141 return testing_cb(iface, pkt);
142 }
143 #endif
144
145 ppp_update_rx_stats(iface, pkt, net_pkt_get_len(pkt));
146
147 if (CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG) {
148 net_pkt_hexdump(pkt, "recv L2");
149 }
150
151 verdict = process_ppp_msg(iface, pkt);
152
153 switch (verdict) {
154 case NET_OK:
155 net_pkt_unref(pkt);
156 break;
157 case NET_DROP:
158 ppp_stats_update_drop_rx(iface);
159 break;
160 case NET_CONTINUE:
161 break;
162 }
163
164 return verdict;
165 }
166
ppp_send(struct net_if * iface,struct net_pkt * pkt)167 static int ppp_send(struct net_if *iface, struct net_pkt *pkt)
168 {
169 const struct ppp_api *api = net_if_get_device(iface)->api;
170 struct ppp_context *ctx = net_if_l2_data(iface);
171 int ret;
172
173 if (CONFIG_NET_L2_PPP_LOG_LEVEL >= LOG_LEVEL_DBG) {
174 net_pkt_hexdump(pkt, "send L2");
175 }
176
177 /* If PPP is not yet ready, then just give error to caller as there
178 * is no way to send before the PPP handshake is finished.
179 */
180 if (ctx->phase != PPP_RUNNING && !net_pkt_is_ppp(pkt)) {
181 return -ENETDOWN;
182 }
183
184 /* PPP drivers only support IP packet types, therefore in order to be
185 * able to use AF_PACKET family sockets with PPP, we need to translate
186 * L2 proto type to packet family.
187 */
188 if (IS_ENABLED(CONFIG_NET_SOCKETS_PACKET) &&
189 net_pkt_family(pkt) == AF_PACKET) {
190 switch (net_pkt_ll_proto_type(pkt)) {
191 case ETH_P_IP:
192 net_pkt_set_family(pkt, AF_INET);
193 break;
194 case ETH_P_IPV6:
195 net_pkt_set_family(pkt, AF_INET6);
196 break;
197 default:
198 return -EPROTONOSUPPORT;
199 }
200 }
201
202 ret = net_l2_send(api->send, net_if_get_device(iface), iface, pkt);
203 if (!ret) {
204 ret = net_pkt_get_len(pkt);
205 ppp_update_tx_stats(iface, pkt, ret);
206 net_pkt_unref(pkt);
207 }
208
209 return ret;
210 }
211
ppp_flags(struct net_if * iface)212 static enum net_l2_flags ppp_flags(struct net_if *iface)
213 {
214 struct ppp_context *ctx = net_if_l2_data(iface);
215
216 return ctx->ppp_l2_flags;
217 }
218
ppp_open_async(struct ppp_context * ctx)219 static void ppp_open_async(struct ppp_context *ctx)
220 {
221 ppp_change_phase(ctx, PPP_ESTABLISH);
222
223 if (ppp_lcp) {
224 NET_DBG("Starting LCP");
225 ppp_lcp->lower_up(ctx);
226 ppp_lcp->open(ctx);
227 }
228 }
229
ppp_up(struct net_if * iface)230 static int ppp_up(struct net_if *iface)
231 {
232 const struct ppp_api *ppp = net_if_get_device(iface)->api;
233
234 if (ppp->start) {
235 ppp->start(net_if_get_device(iface));
236 }
237
238 return 0;
239 }
240
ppp_lcp_close(struct ppp_context * ctx)241 static int ppp_lcp_close(struct ppp_context *ctx)
242 {
243 if (ppp_lcp == NULL) {
244 ppp_change_phase(ctx, PPP_DEAD);
245 }
246
247 if (ctx->phase == PPP_DEAD) {
248 return 0;
249 }
250
251 k_sem_reset(&ctx->wait_ppp_link_terminated);
252 ppp_lcp->close(ctx, "L2 Disabled");
253 return k_sem_take(&ctx->wait_ppp_link_terminated,
254 K_MSEC(CONFIG_NET_L2_PPP_TIMEOUT *
255 (1 + CONFIG_NET_L2_PPP_MAX_TERMINATE_REQ_RETRANSMITS)));
256 }
257
ppp_lcp_lower_down_async(struct ppp_context * ctx)258 static void ppp_lcp_lower_down_async(struct ppp_context *ctx)
259 {
260 if (ctx->phase == PPP_DEAD) {
261 return;
262 }
263
264 if (ppp_lcp == NULL) {
265 ppp_change_phase(ctx, PPP_DEAD);
266 } else {
267 ppp_lcp->lower_down(ctx);
268 }
269 }
270
ppp_lcp_lower_down(struct ppp_context * ctx)271 static int ppp_lcp_lower_down(struct ppp_context *ctx)
272 {
273 if (ppp_lcp == NULL) {
274 ppp_change_phase(ctx, PPP_DEAD);
275 }
276
277 if (ctx->phase == PPP_DEAD) {
278 return 0;
279 }
280
281 k_sem_reset(&ctx->wait_ppp_link_down);
282 ppp_lcp->lower_down(ctx);
283 return k_sem_take(&ctx->wait_ppp_link_down, K_MSEC(CONFIG_NET_L2_PPP_TIMEOUT));
284 }
285
286 /* Bring down network interface by terminating all protocols */
ppp_down(struct net_if * iface)287 static int ppp_down(struct net_if *iface)
288 {
289 const struct ppp_api *ppp = net_if_get_device(iface)->api;
290 struct ppp_context *ctx = net_if_l2_data(iface);
291
292 if (net_if_is_carrier_ok(iface)) {
293 /* Terminate protocols and close LCP */
294 if (ppp_lcp_close(ctx) < 0) {
295 return -EAGAIN;
296 }
297 } else {
298 /* Terminate protocols */
299 if (ppp_lcp_lower_down(ctx) < 0) {
300 return -EAGAIN;
301 }
302 }
303
304 if (ppp->stop) {
305 /* Inform L2 PPP device that PPP link is down */
306 ppp->stop(net_if_get_device(iface));
307 }
308
309 return 0;
310 }
311
ppp_enable(struct net_if * iface,bool state)312 static int ppp_enable(struct net_if *iface, bool state)
313 {
314 struct ppp_context *ctx = net_if_l2_data(iface);
315 int ret;
316
317 /* Set the desired network interface state */
318 ctx->is_enabled = state;
319
320 /* Attempt to enter desired state */
321 if (state) {
322 ret = ppp_up(iface);
323 } else {
324 ret = ppp_down(iface);
325 }
326
327 if (ret < 0) {
328 /* Reset the desired state */
329 ctx->is_enabled = !state;
330 }
331
332 return ret;
333 }
334
335 NET_L2_INIT(PPP_L2, ppp_recv, ppp_send, ppp_enable, ppp_flags);
336
337 #if defined(CONFIG_NET_SHELL)
get_ppp_context(int idx,struct ppp_context ** ctx,struct net_if ** iface)338 static int get_ppp_context(int idx, struct ppp_context **ctx,
339 struct net_if **iface)
340 {
341 *iface = net_if_get_by_index(idx);
342
343 if (!*iface) {
344 return -ENOENT;
345 }
346
347 if (net_if_l2(*iface) != &NET_L2_GET_NAME(PPP)) {
348 return -ENODEV;
349 }
350
351 *ctx = net_if_l2_data(*iface);
352
353 return 0;
354 }
355
echo_reply_handler(void * user_data,size_t user_data_len)356 static void echo_reply_handler(void *user_data, size_t user_data_len)
357 {
358 struct ppp_context *ctx = user_data;
359 uint32_t end_time = k_cycle_get_32();
360 uint32_t time_diff;
361
362 time_diff = end_time - ctx->shell.echo_req_data;
363 ctx->shell.echo_req_data =
364 k_cyc_to_ns_floor64(time_diff) / 1000;
365
366 k_sem_give(&ctx->shell.wait_echo_reply);
367 }
368
net_ppp_ping(int idx,int32_t timeout)369 int net_ppp_ping(int idx, int32_t timeout)
370 {
371 struct ppp_context *ctx;
372 struct net_if *iface;
373 int ret;
374
375 ret = get_ppp_context(idx, &ctx, &iface);
376 if (ret < 0) {
377 return ret;
378 }
379
380 ctx->shell.echo_req_data = k_cycle_get_32();
381 ctx->shell.echo_reply.cb = echo_reply_handler;
382 ctx->shell.echo_reply.user_data = ctx;
383 ctx->shell.echo_reply.user_data_len = sizeof(ctx);
384
385 ret = ppp_send_pkt(&ctx->lcp.fsm, iface, PPP_ECHO_REQ, 0,
386 UINT_TO_POINTER(ctx->shell.echo_req_data),
387 sizeof(ctx->shell.echo_req_data));
388 if (ret < 0) {
389 return ret;
390 }
391
392 ret = k_sem_take(&ctx->shell.wait_echo_reply, K_MSEC(timeout));
393
394 ctx->shell.echo_reply.cb = NULL;
395
396 if (ret < 0) {
397 return ret;
398 }
399
400 /* Returns amount of microseconds waited */
401 return ctx->shell.echo_req_data;
402 }
403
net_ppp_context_get(int idx)404 struct ppp_context *net_ppp_context_get(int idx)
405 {
406 struct ppp_context *ctx;
407 struct net_if *iface;
408 int ret;
409
410 if (idx == 0) {
411 iface = net_if_get_first_by_type(&NET_L2_GET_NAME(PPP));
412 if (!iface) {
413 return NULL;
414 }
415
416 return net_if_l2_data(iface);
417 }
418
419 ret = get_ppp_context(idx, &ctx, &iface);
420 if (ret < 0) {
421 return NULL;
422 }
423
424 return ctx;
425 }
426 #endif
427
ppp_lcp_get(void)428 const struct ppp_protocol_handler *ppp_lcp_get(void)
429 {
430 return ppp_lcp;
431 }
432
ppp_queue_pkt(struct net_pkt * pkt)433 void ppp_queue_pkt(struct net_pkt *pkt)
434 {
435 k_fifo_put(&tx_queue, pkt);
436 }
437
tx_handler(void * p1,void * p2,void * p3)438 static void tx_handler(void *p1, void *p2, void *p3)
439 {
440 ARG_UNUSED(p1);
441 ARG_UNUSED(p2);
442 ARG_UNUSED(p3);
443
444 struct net_pkt *pkt;
445 int ret;
446
447 NET_DBG("PPP TX started");
448
449 k_thread_name_set(NULL, "ppp_tx");
450
451 while (1) {
452 pkt = k_fifo_get(&tx_queue, K_FOREVER);
453 if (pkt == NULL) {
454 continue;
455 }
456
457 ret = net_send_data(pkt);
458 if (ret < 0) {
459 net_pkt_unref(pkt);
460 }
461 }
462 }
463
net_ppp_mgmt_evt_handler(struct net_mgmt_event_callback * cb,uint32_t mgmt_event,struct net_if * iface)464 static void net_ppp_mgmt_evt_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event,
465 struct net_if *iface)
466 {
467 struct ppp_context *ctx;
468
469 if (net_if_l2(iface) != &NET_L2_GET_NAME(PPP)) {
470 return;
471 }
472
473 ctx = net_if_l2_data(iface);
474
475 if (net_if_is_carrier_ok(iface)) {
476 ppp_mgmt_raise_carrier_on_event(iface);
477 } else {
478 ppp_mgmt_raise_carrier_off_event(iface);
479 }
480
481 if (mgmt_event == NET_EVENT_IF_UP) {
482 ppp_open_async(ctx);
483 return;
484 }
485
486 if ((mgmt_event == NET_EVENT_IF_DOWN) && (!net_if_is_carrier_ok(iface))) {
487 ppp_lcp_lower_down_async(ctx);
488 }
489 }
490
net_ppp_init(struct net_if * iface)491 void net_ppp_init(struct net_if *iface)
492 {
493 struct ppp_context *ctx = net_if_l2_data(iface);
494 uint8_t count = 0;
495
496 NET_DBG("Initializing PPP L2 %p for iface %p", ctx, iface);
497
498 memset(ctx, 0, sizeof(*ctx));
499
500 ctx->ppp_l2_flags = NET_L2_MULTICAST | NET_L2_POINT_TO_POINT;
501 ctx->iface = iface;
502 k_sem_init(&ctx->wait_ppp_link_terminated, 0, 1);
503 k_sem_init(&ctx->wait_ppp_link_down, 0, 1);
504
505 #if defined(CONFIG_NET_SHELL)
506 k_sem_init(&ctx->shell.wait_echo_reply, 0, K_SEM_MAX_LIMIT);
507 #endif
508
509 net_mgmt_init_event_callback(&ctx->mgmt_evt_cb, net_ppp_mgmt_evt_handler,
510 (NET_EVENT_IF_UP | NET_EVENT_IF_DOWN));
511
512 net_mgmt_add_event_callback(&ctx->mgmt_evt_cb);
513
514 STRUCT_SECTION_FOREACH(ppp_protocol_handler, proto) {
515 if (proto->protocol == PPP_LCP) {
516 ppp_lcp = proto;
517 }
518
519 proto->init(ctx);
520 count++;
521 }
522
523 if (count == 0) {
524 NET_ERR("There are no PPP protocols configured!");
525 return;
526 }
527
528 if (ppp_lcp == NULL) {
529 NET_ERR("No LCP found!");
530 return;
531 }
532
533 ctx->is_ready_to_serve = true;
534 }
535