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_DECLARE(net_l2_ppp, CONFIG_NET_L2_PPP_LOG_LEVEL);
9
10 #include <zephyr/net/net_core.h>
11 #include <zephyr/net/net_pkt.h>
12 #include <zephyr/net/net_if.h>
13
14 #include <zephyr/net/ppp.h>
15 #include <zephyr/random/rand32.h>
16
17 #include "net_private.h"
18
19 #include "ppp_internal.h"
20
21 /* This timeout is in milliseconds */
22 #define FSM_TIMEOUT K_MSEC(CONFIG_NET_L2_PPP_TIMEOUT)
23
24 #define MAX_NACK_LOOPS CONFIG_NET_L2_PPP_MAX_NACK_LOOPS
25
ppp_fsm_ctx(struct ppp_fsm * fsm)26 struct ppp_context *ppp_fsm_ctx(struct ppp_fsm *fsm)
27 {
28 if (fsm->protocol == PPP_LCP) {
29 return CONTAINER_OF(fsm, struct ppp_context, lcp.fsm);
30 #if defined(CONFIG_NET_IPV4)
31 } else if (fsm->protocol == PPP_IPCP) {
32 return CONTAINER_OF(fsm, struct ppp_context, ipcp.fsm);
33 #endif
34 #if defined(CONFIG_NET_IPV6)
35 } else if (fsm->protocol == PPP_IPV6CP) {
36 return CONTAINER_OF(fsm, struct ppp_context, ipv6cp.fsm);
37 #endif
38 #if defined(CONFIG_NET_L2_PPP_PAP)
39 } else if (fsm->protocol == PPP_PAP) {
40 return CONTAINER_OF(fsm, struct ppp_context, pap.fsm);
41 #endif
42 }
43
44 return NULL;
45 }
46
ppp_fsm_iface(struct ppp_fsm * fsm)47 struct net_if *ppp_fsm_iface(struct ppp_fsm *fsm)
48 {
49 struct ppp_context *ctx = ppp_fsm_ctx(fsm);
50
51 NET_ASSERT(ctx->iface);
52
53 return ctx->iface;
54 }
55
fsm_send_configure_req(struct ppp_fsm * fsm,bool retransmit)56 static void fsm_send_configure_req(struct ppp_fsm *fsm, bool retransmit)
57 {
58 struct net_pkt *pkt = NULL;
59
60 if (fsm->state != PPP_ACK_RECEIVED &&
61 fsm->state != PPP_ACK_SENT &&
62 fsm->state != PPP_REQUEST_SENT) {
63 /* If we are not negotiating options, then reset them */
64 if (fsm->cb.config_info_reset) {
65 fsm->cb.config_info_reset(fsm);
66 }
67
68 fsm->recv_nack_loops = 0;
69 fsm->nack_loops = 0;
70 }
71
72 if (!retransmit) {
73 fsm->retransmits = MAX_CONFIGURE_REQ;
74 fsm->req_id = ++fsm->id;
75 }
76
77 fsm->ack_received = false;
78
79 if (fsm->cb.config_info_add) {
80 pkt = fsm->cb.config_info_add(fsm);
81 }
82
83 NET_DBG("[%s/%p] Sending %s (%d) id %d to peer while in %s (%d)",
84 fsm->name, fsm, ppp_pkt_type2str(PPP_CONFIGURE_REQ),
85 PPP_CONFIGURE_REQ, fsm->req_id, ppp_state_str(fsm->state),
86 fsm->state);
87
88 (void)ppp_send_pkt(fsm, NULL, PPP_CONFIGURE_REQ, fsm->req_id,
89 pkt, pkt ? net_pkt_get_len(pkt) : 0);
90
91 fsm->retransmits--;
92
93 (void)k_work_reschedule(&fsm->timer, FSM_TIMEOUT);
94 }
95
ppp_fsm_timeout(struct k_work * work)96 static void ppp_fsm_timeout(struct k_work *work)
97 {
98 struct k_work_delayable *dwork = k_work_delayable_from_work(work);
99 struct ppp_fsm *fsm = CONTAINER_OF(dwork, struct ppp_fsm, timer);
100
101 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
102 ppp_state_str(fsm->state), fsm->state);
103
104 switch (fsm->state) {
105 case PPP_ACK_RECEIVED:
106 case PPP_ACK_SENT:
107 case PPP_REQUEST_SENT:
108 if (fsm->retransmits <= 0) {
109 NET_DBG("[%s/%p] %s retransmit limit %d reached",
110 fsm->name, fsm,
111 ppp_pkt_type2str(PPP_CONFIGURE_REQ),
112 fsm->retransmits);
113
114 ppp_change_state(fsm, PPP_STOPPED);
115
116 if (fsm->cb.finished) {
117 fsm->cb.finished(fsm);
118 }
119 } else {
120 if (fsm->cb.retransmit) {
121 fsm->cb.retransmit(fsm);
122 }
123
124 fsm_send_configure_req(fsm, true);
125
126 if (fsm->state == PPP_ACK_RECEIVED) {
127 ppp_change_state(fsm, PPP_REQUEST_SENT);
128 }
129 }
130
131 break;
132
133 case PPP_CLOSING:
134 case PPP_STOPPING:
135 if (fsm->retransmits <= 0) {
136 ppp_change_state(fsm,
137 fsm->state == PPP_CLOSING ?
138 PPP_CLOSED : PPP_STOPPED);
139
140 if (fsm->cb.finished) {
141 fsm->cb.finished(fsm);
142 }
143 } else {
144 fsm->req_id = ++fsm->id;
145
146 ppp_send_pkt(fsm, NULL, PPP_TERMINATE_REQ, fsm->req_id,
147 fsm->terminate_reason,
148 strlen(fsm->terminate_reason));
149
150 fsm->retransmits--;
151
152 (void)k_work_reschedule(&fsm->timer, FSM_TIMEOUT);
153 }
154
155 break;
156
157 default:
158 NET_DBG("[%s/%p] %s state %s (%d)", fsm->name, fsm, "Invalid",
159 ppp_state_str(fsm->state), fsm->state);
160 break;
161 }
162 }
163
ppp_fsm_init(struct ppp_fsm * fsm,uint16_t protocol)164 void ppp_fsm_init(struct ppp_fsm *fsm, uint16_t protocol)
165 {
166 fsm->protocol = protocol;
167 fsm->state = PPP_INITIAL;
168 fsm->flags = 0U;
169
170 k_work_init_delayable(&fsm->timer, ppp_fsm_timeout);
171 }
172
fsm_down(struct ppp_fsm * fsm)173 static void fsm_down(struct ppp_fsm *fsm)
174 {
175 size_t i;
176
177 for (i = 0; i < fsm->my_options.count; i++) {
178 fsm->my_options.data[i].flags = 0;
179 }
180
181 if (fsm->cb.down) {
182 fsm->cb.down(fsm);
183 }
184 }
185
terminate(struct ppp_fsm * fsm,enum ppp_state next_state)186 static void terminate(struct ppp_fsm *fsm, enum ppp_state next_state)
187 {
188 if (fsm->state != PPP_OPENED) {
189 k_work_cancel_delayable(&fsm->timer);
190 } else {
191 fsm_down(fsm);
192 }
193
194 fsm->retransmits = MAX_TERMINATE_REQ;
195 fsm->req_id = ++fsm->id;
196
197 (void)ppp_send_pkt(fsm, NULL, PPP_TERMINATE_REQ, fsm->req_id,
198 fsm->terminate_reason,
199 strlen(fsm->terminate_reason));
200
201 if (fsm->retransmits == 0) {
202 ppp_change_state(fsm, next_state);
203
204 if (fsm->cb.finished) {
205 fsm->cb.finished(fsm);
206 }
207
208 return;
209 }
210
211 (void)k_work_reschedule(&fsm->timer, FSM_TIMEOUT);
212
213 fsm->retransmits--;
214
215 ppp_change_state(fsm, next_state);
216 }
217
ppp_fsm_close(struct ppp_fsm * fsm,const uint8_t * reason)218 void ppp_fsm_close(struct ppp_fsm *fsm, const uint8_t *reason)
219 {
220 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
221 ppp_state_str(fsm->state), fsm->state);
222
223 switch (fsm->state) {
224 case PPP_ACK_RECEIVED:
225 case PPP_ACK_SENT:
226 case PPP_OPENED:
227 case PPP_REQUEST_SENT:
228 if (reason) {
229 int len = strlen(reason);
230
231 len = MIN(sizeof(fsm->terminate_reason) - 1, len);
232 strncpy(fsm->terminate_reason, reason, len);
233 }
234
235 terminate(fsm, PPP_CLOSING);
236 break;
237
238 case PPP_INITIAL:
239 case PPP_STARTING:
240 ppp_change_state(fsm, PPP_INITIAL);
241 break;
242
243 case PPP_STOPPED:
244 ppp_change_state(fsm, PPP_CLOSED);
245 break;
246
247 case PPP_STOPPING:
248 ppp_change_state(fsm, PPP_CLOSING);
249 break;
250
251 default:
252 NET_DBG("[%s/%p] %s state %s (%d)", fsm->name, fsm, "Invalid",
253 ppp_state_str(fsm->state), fsm->state);
254 break;
255 }
256 }
257
ppp_fsm_lower_down(struct ppp_fsm * fsm)258 void ppp_fsm_lower_down(struct ppp_fsm *fsm)
259 {
260 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
261 ppp_state_str(fsm->state), fsm->state);
262
263 switch (fsm->state) {
264 case PPP_ACK_RECEIVED:
265 case PPP_ACK_SENT:
266 case PPP_REQUEST_SENT:
267 case PPP_STOPPING:
268 ppp_change_state(fsm, PPP_STARTING);
269 k_work_cancel_delayable(&fsm->timer);
270 break;
271
272 case PPP_CLOSED:
273 ppp_change_state(fsm, PPP_INITIAL);
274 break;
275
276 case PPP_CLOSING:
277 ppp_change_state(fsm, PPP_INITIAL);
278 k_work_cancel_delayable(&fsm->timer);
279 break;
280
281 case PPP_OPENED:
282 ppp_change_state(fsm, PPP_STARTING);
283 fsm_down(fsm);
284
285 break;
286
287 case PPP_STOPPED:
288 ppp_change_state(fsm, PPP_STARTING);
289 if (fsm->cb.starting) {
290 fsm->cb.starting(fsm);
291 }
292
293 break;
294
295 default:
296 NET_DBG("[%s/%p] %s state %s (%d)", fsm->name, fsm, "Invalid",
297 ppp_state_str(fsm->state), fsm->state);
298 break;
299 }
300 }
301
ppp_fsm_lower_up(struct ppp_fsm * fsm)302 void ppp_fsm_lower_up(struct ppp_fsm *fsm)
303 {
304 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
305 ppp_state_str(fsm->state), fsm->state);
306
307 switch (fsm->state) {
308 case PPP_CLOSED:
309 break;
310
311 case PPP_INITIAL:
312 ppp_change_state(fsm, PPP_CLOSED);
313 break;
314
315 case PPP_STARTING:
316 fsm_send_configure_req(fsm, false);
317 ppp_change_state(fsm, PPP_REQUEST_SENT);
318
319 break;
320
321 default:
322 NET_DBG("[%s/%p] %s state %s (%d)", fsm->name, fsm, "Invalid",
323 ppp_state_str(fsm->state), fsm->state);
324 break;
325 }
326 }
327
ppp_fsm_open(struct ppp_fsm * fsm)328 void ppp_fsm_open(struct ppp_fsm *fsm)
329 {
330 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
331 ppp_state_str(fsm->state), fsm->state);
332
333 switch (fsm->state) {
334 case PPP_CLOSED:
335 ppp_change_state(fsm, PPP_REQUEST_SENT);
336 fsm_send_configure_req(fsm, false);
337 break;
338
339 case PPP_CLOSING:
340 ppp_change_state(fsm, PPP_STOPPING);
341 if (fsm->flags & FSM_RESTART) {
342 ppp_fsm_lower_down(fsm);
343 ppp_fsm_lower_up(fsm);
344 }
345
346 break;
347
348 case PPP_INITIAL:
349 ppp_change_state(fsm, PPP_STARTING);
350 if (fsm->cb.starting) {
351 fsm->cb.starting(fsm);
352 }
353
354 break;
355
356 case PPP_OPENED:
357 case PPP_STOPPED:
358 if (fsm->flags & FSM_RESTART) {
359 ppp_fsm_lower_down(fsm);
360 ppp_fsm_lower_up(fsm);
361 }
362
363 break;
364
365 default:
366 NET_DBG("[%s/%p] %s state %s (%d)", fsm->name, fsm, "Invalid",
367 ppp_state_str(fsm->state), fsm->state);
368 break;
369 }
370 }
371
ppp_send_pkt(struct ppp_fsm * fsm,struct net_if * iface,enum ppp_packet_type type,uint8_t id,void * data,uint32_t data_len)372 int ppp_send_pkt(struct ppp_fsm *fsm, struct net_if *iface,
373 enum ppp_packet_type type, uint8_t id,
374 void *data, uint32_t data_len)
375 {
376 /* Note that the data parameter is the received PPP packet if
377 * we want to send PROTOCOL or CODE reject packet.
378 */
379 struct net_pkt *req_pkt = data;
380 uint16_t protocol = 0;
381 size_t len = 0;
382 struct ppp_packet ppp;
383 struct net_pkt *pkt = NULL;
384 int ret;
385
386 if (!iface) {
387 if (!fsm) {
388 return -ENOENT;
389 }
390
391 iface = ppp_fsm_iface(fsm);
392 }
393
394 if (fsm) {
395 protocol = fsm->protocol;
396 }
397
398 switch (type) {
399 case PPP_CODE_REJ: {
400 struct ppp_context *ctx = ppp_fsm_ctx(fsm);
401
402 len = net_pkt_get_len(req_pkt);
403 len = MIN(len, ctx->lcp.my_options.mru);
404 break;
405 }
406
407 case PPP_CONFIGURE_ACK:
408 case PPP_CONFIGURE_NACK:
409 case PPP_CONFIGURE_REJ:
410 case PPP_CONFIGURE_REQ:
411 pkt = data;
412 /* 2 + 1 + 1 (configure-[req|ack|nack|rej]) +
413 * data_len (options)
414 */
415 len = sizeof(ppp) + data_len;
416 break;
417
418 case PPP_DISCARD_REQ:
419 break;
420
421 case PPP_ECHO_REQ:
422 len = sizeof(ppp) + sizeof(uint32_t) + data_len;
423 break;
424
425 case PPP_ECHO_REPLY:
426 len = sizeof(ppp) + net_pkt_remaining_data(req_pkt);
427 break;
428
429 case PPP_PROTOCOL_REJ:
430 len = sizeof(ppp) + sizeof(uint16_t) +
431 net_pkt_remaining_data(req_pkt);
432 protocol = PPP_LCP;
433 break;
434
435 case PPP_TERMINATE_REQ:
436 case PPP_TERMINATE_ACK:
437 len = sizeof(ppp);
438 break;
439
440 default:
441 break;
442 }
443
444 if (len < sizeof(ppp)) {
445 return -EINVAL;
446 }
447
448 ppp.code = type;
449 ppp.id = id;
450 ppp.length = htons(len);
451
452 if (!pkt) {
453 pkt = net_pkt_alloc_with_buffer(iface,
454 sizeof(uint16_t) + len,
455 AF_UNSPEC, 0,
456 PPP_BUF_ALLOC_TIMEOUT);
457 if (!pkt) {
458 goto out_of_mem;
459 }
460 } else {
461 struct net_buf *buf;
462
463 buf = net_pkt_get_reserve_tx_data(sizeof(uint16_t) + len,
464 PPP_BUF_ALLOC_TIMEOUT);
465 if (!buf) {
466 LOG_ERR("failed to allocate buffer");
467 goto out_of_mem;
468 }
469
470 net_pkt_frag_insert(pkt, buf);
471 net_pkt_cursor_init(pkt);
472 }
473
474 ret = net_pkt_write_be16(pkt, protocol);
475 if (ret < 0) {
476 goto out_of_mem;
477 }
478
479 ret = net_pkt_write(pkt, &ppp, sizeof(ppp));
480 if (ret < 0) {
481 goto out_of_mem;
482 }
483
484 if (type == PPP_CODE_REJ) {
485 if (!req_pkt) {
486 goto out_of_mem;
487 }
488
489 net_pkt_cursor_init(req_pkt);
490 net_pkt_copy(pkt, req_pkt, len);
491
492 } else if (type == PPP_ECHO_REQ) {
493 struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
494 lcp.fsm);
495 if (ctx->lcp.magic) {
496 ctx->lcp.magic = sys_rand32_get();
497 }
498
499 ret = net_pkt_write_be32(pkt, ctx->lcp.magic);
500 if (ret < 0) {
501 goto out_of_mem;
502 }
503
504 data_len = MIN(data_len, ctx->lcp.my_options.mru);
505 if (data_len > 0) {
506 if (data_len == sizeof(uint32_t)) {
507 ret = net_pkt_write_be32(pkt,
508 POINTER_TO_UINT(data));
509 } else {
510 ret = net_pkt_write(pkt, data, data_len);
511 }
512
513 if (ret < 0) {
514 goto out_of_mem;
515 }
516 }
517 } else if (type == PPP_ECHO_REPLY) {
518 net_pkt_copy(pkt, req_pkt, len);
519 } else if (type == PPP_PROTOCOL_REJ) {
520 net_pkt_cursor_init(req_pkt);
521 net_pkt_copy(pkt, req_pkt, len);
522 }
523
524 NET_DBG("[%s/%p] Sending %zd bytes pkt %p (options len %d)",
525 fsm ? fsm->name : "?", fsm, net_pkt_get_len(pkt), pkt,
526 data_len);
527
528 net_pkt_set_ppp(pkt, true);
529
530 if (fsm) {
531 /* Do not call net_send_data() directly in order to make this
532 * thread run before the sending happens. If we call the
533 * net_send_data() from this thread, then in fast link (like
534 * when running inside QEMU) the reply might arrive before we
535 * have returned from this function. That is bad because the
536 * fsm would be in wrong state and the received pkt is dropped.
537 */
538 ppp_queue_pkt(pkt);
539 } else {
540 ret = net_send_data(pkt);
541 if (ret < 0) {
542 net_pkt_unref(pkt);
543 }
544 }
545
546 return 0;
547
548 out_of_mem:
549 if (pkt) {
550 net_pkt_unref(pkt);
551 }
552
553 return -ENOMEM;
554 }
555
fsm_recv_configure_req(struct ppp_fsm * fsm,uint8_t id,struct net_pkt * pkt,uint16_t remaining_len)556 static enum net_verdict fsm_recv_configure_req(struct ppp_fsm *fsm,
557 uint8_t id,
558 struct net_pkt *pkt,
559 uint16_t remaining_len)
560 {
561 struct net_pkt *out = NULL;
562 int len = 0;
563 enum ppp_packet_type code;
564
565 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
566 ppp_state_str(fsm->state), fsm->state);
567
568 switch (fsm->state) {
569 case PPP_ACK_SENT:
570 case PPP_ACK_RECEIVED:
571 break;
572
573 case PPP_CLOSED:
574 (void)ppp_send_pkt(fsm, net_pkt_iface(pkt), PPP_TERMINATE_ACK,
575 id, NULL, 0);
576 return NET_OK;
577
578 case PPP_CLOSING:
579 case PPP_STOPPING:
580 return NET_OK;
581
582 case PPP_OPENED:
583 fsm_down(fsm);
584
585 fsm_send_configure_req(fsm, false);
586 ppp_change_state(fsm, PPP_REQUEST_SENT);
587 break;
588
589 case PPP_REQUEST_SENT:
590 /* Received request while waiting ACK */
591 break;
592
593 case PPP_STOPPED:
594 fsm_send_configure_req(fsm, false);
595 ppp_change_state(fsm, PPP_REQUEST_SENT);
596 break;
597
598 default:
599 NET_DBG("[%s/%p] %s state %s (%d)", fsm->name, fsm, "Invalid",
600 ppp_state_str(fsm->state), fsm->state);
601 return NET_DROP;
602 }
603
604 out = net_pkt_alloc_with_buffer(net_pkt_iface(pkt),
605 sizeof(uint16_t) + sizeof(uint16_t) +
606 sizeof(uint8_t) + sizeof(uint8_t) +
607 remaining_len,
608 AF_UNSPEC, 0, PPP_BUF_ALLOC_TIMEOUT);
609 if (!out) {
610 return NET_DROP;
611 }
612
613 net_pkt_cursor_init(out);
614
615 if (fsm->cb.config_info_req) {
616 int ret;
617
618 ret = fsm->cb.config_info_req(fsm, pkt, remaining_len, out);
619 if (ret < 0) {
620 goto unref_out_pkt;
621 }
622
623 if (fsm->nack_loops >= MAX_NACK_LOOPS &&
624 ret == PPP_CONFIGURE_NACK) {
625 ret = PPP_CONFIGURE_REJ;
626 }
627
628 code = ret;
629 len = net_pkt_get_len(out);
630 } else if (remaining_len) {
631 code = PPP_CONFIGURE_REJ;
632
633 net_pkt_copy(out, pkt, remaining_len);
634 len = remaining_len;
635 } else {
636 code = PPP_CONFIGURE_ACK;
637 }
638
639 NET_DBG("[%s/%p] Sending %s (%d) id %d to peer while in %s (%d)",
640 fsm->name, fsm, ppp_pkt_type2str(code), code, id,
641 ppp_state_str(fsm->state), fsm->state);
642
643 (void)ppp_send_pkt(fsm, NULL, code, id, out, len);
644
645 if (code == PPP_CONFIGURE_ACK) {
646 if (fsm->state == PPP_ACK_RECEIVED) {
647 k_work_cancel_delayable(&fsm->timer);
648
649 ppp_change_state(fsm, PPP_OPENED);
650
651 if (fsm->cb.up) {
652 fsm->cb.up(fsm);
653 }
654 } else {
655 ppp_change_state(fsm, PPP_ACK_SENT);
656 }
657
658 fsm->nack_loops = 0;
659 } else {
660 if (fsm->state != PPP_ACK_RECEIVED) {
661 ppp_change_state(fsm, PPP_REQUEST_SENT);
662 }
663
664 if (code == PPP_CONFIGURE_NACK) {
665 fsm->nack_loops++;
666 }
667 }
668
669 return NET_OK;
670
671 unref_out_pkt:
672 net_pkt_unref(out);
673
674 return NET_DROP;
675 }
676
fsm_recv_configure_ack(struct ppp_fsm * fsm,uint8_t id,struct net_pkt * pkt,uint16_t remaining_len)677 static enum net_verdict fsm_recv_configure_ack(struct ppp_fsm *fsm, uint8_t id,
678 struct net_pkt *pkt,
679 uint16_t remaining_len)
680 {
681 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
682 ppp_state_str(fsm->state), fsm->state);
683
684 if (id != fsm->req_id || fsm->ack_received) {
685 return NET_DROP;
686 }
687
688 if (fsm->cb.config_info_ack) {
689 if (fsm->cb.config_info_ack(fsm, pkt, remaining_len) < 0) {
690 NET_DBG("[%s/%p] %s %s received", fsm->name, fsm,
691 "Invalid",
692 ppp_pkt_type2str(PPP_CONFIGURE_ACK));
693 return NET_DROP;
694 }
695 }
696
697 fsm->ack_received = true;
698 fsm->recv_nack_loops = 0;
699
700 switch (fsm->state) {
701 case PPP_ACK_RECEIVED:
702 k_work_cancel_delayable(&fsm->timer);
703 fsm_send_configure_req(fsm, false);
704 ppp_change_state(fsm, PPP_REQUEST_SENT);
705 break;
706
707 case PPP_ACK_SENT:
708 k_work_cancel_delayable(&fsm->timer);
709 ppp_change_state(fsm, PPP_OPENED);
710 fsm->retransmits = MAX_CONFIGURE_REQ;
711 if (fsm->cb.up) {
712 fsm->cb.up(fsm);
713 }
714
715 break;
716
717 case PPP_CLOSED:
718 case PPP_STOPPED:
719 (void)ppp_send_pkt(fsm, net_pkt_iface(pkt), PPP_TERMINATE_ACK,
720 id, NULL, 0);
721 break;
722
723 case PPP_OPENED:
724 fsm_down(fsm);
725
726 fsm_send_configure_req(fsm, false);
727 ppp_change_state(fsm, PPP_REQUEST_SENT);
728 break;
729
730 case PPP_REQUEST_SENT:
731 ppp_change_state(fsm, PPP_ACK_RECEIVED);
732 fsm->retransmits = MAX_CONFIGURE_REQ;
733 break;
734
735 default:
736 NET_DBG("[%s/%p] %s state %s (%d)", fsm->name, fsm, "Invalid",
737 ppp_state_str(fsm->state), fsm->state);
738 return NET_DROP;
739 }
740
741 return NET_OK;
742 }
743
fsm_recv_configure_nack_rej(struct ppp_fsm * fsm,enum ppp_packet_type code,uint8_t id,struct net_pkt * pkt,uint16_t length)744 static enum net_verdict fsm_recv_configure_nack_rej(struct ppp_fsm *fsm,
745 enum ppp_packet_type code,
746 uint8_t id,
747 struct net_pkt *pkt,
748 uint16_t length)
749 {
750 bool ret = false;
751
752 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
753 ppp_state_str(fsm->state), fsm->state);
754
755 if (id != fsm->req_id || fsm->ack_received) {
756 return NET_DROP;
757 }
758
759 if (code == PPP_CONFIGURE_NACK) {
760 bool rejected = false;
761
762 fsm->recv_nack_loops++;
763
764 if (fsm->recv_nack_loops >= MAX_NACK_LOOPS) {
765 rejected = true;
766 }
767
768 if (fsm->cb.config_info_nack) {
769 int err;
770
771 err = fsm->cb.config_info_nack(fsm, pkt, length,
772 rejected);
773 if (err < 0) {
774 NET_DBG("[%s/%p] %s failed (%d)",
775 fsm->name, fsm, "Nack", err);
776 } else {
777 ret = true;
778 }
779 }
780
781 if (!ret) {
782 NET_DBG("[%s/%p] %s %s (id %d)", fsm->name, fsm,
783 "Invalid", ppp_pkt_type2str(code), id);
784 return NET_DROP;
785 }
786 } else {
787 fsm->recv_nack_loops = 0;
788
789 if (fsm->cb.config_info_rej) {
790 int err;
791
792 err = fsm->cb.config_info_rej(fsm, pkt, length);
793 if (err < 0) {
794 NET_DBG("[%s/%p] %s failed (%d)",
795 fsm->name, fsm, "Reject", err);
796 } else {
797 ret = true;
798 }
799 }
800
801 if (!ret) {
802 NET_DBG("[%s/%p] %s %s (id %d)", fsm->name, fsm,
803 "Invalid", ppp_pkt_type2str(code), id);
804 return NET_DROP;
805 }
806 }
807
808 fsm->ack_received = true;
809
810 switch (fsm->state) {
811 case PPP_ACK_RECEIVED:
812 k_work_cancel_delayable(&fsm->timer);
813 fsm_send_configure_req(fsm, false);
814 ppp_change_state(fsm, PPP_REQUEST_SENT);
815 break;
816
817 case PPP_ACK_SENT:
818 case PPP_REQUEST_SENT:
819 k_work_cancel_delayable(&fsm->timer);
820 fsm_send_configure_req(fsm, false);
821 break;
822
823 case PPP_CLOSED:
824 case PPP_STOPPED:
825 (void)ppp_send_pkt(fsm, net_pkt_iface(pkt), PPP_TERMINATE_ACK,
826 id, NULL, 0);
827 break;
828
829 case PPP_OPENED:
830 fsm_down(fsm);
831
832 fsm_send_configure_req(fsm, false);
833 ppp_change_state(fsm, PPP_REQUEST_SENT);
834 break;
835
836 default:
837 NET_DBG("[%s/%p] %s state %s (%d)", fsm->name, fsm, "Invalid",
838 ppp_state_str(fsm->state), fsm->state);
839 return NET_DROP;
840 }
841
842 return NET_OK;
843 }
844
fsm_recv_terminate_req(struct ppp_fsm * fsm,uint8_t id,struct net_pkt * pkt,uint16_t length)845 static enum net_verdict fsm_recv_terminate_req(struct ppp_fsm *fsm, uint8_t id,
846 struct net_pkt *pkt,
847 uint16_t length)
848 {
849 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
850 ppp_state_str(fsm->state), fsm->state);
851
852 switch (fsm->state) {
853 case PPP_ACK_RECEIVED:
854 case PPP_ACK_SENT:
855 ppp_change_state(fsm, PPP_REQUEST_SENT);
856 break;
857
858 case PPP_OPENED:
859 if (length > 0) {
860 net_pkt_read(pkt, fsm->terminate_reason,
861 MIN(length,
862 sizeof(fsm->terminate_reason) - 1));
863
864 NET_DBG("[%s/%p] %s (%s)",
865 fsm->name, fsm, "Terminated by peer",
866 fsm->terminate_reason);
867 } else {
868 NET_DBG("[%s/%p] Terminated by peer",
869 fsm->name, fsm);
870 }
871
872 fsm->retransmits = 0;
873 ppp_change_state(fsm, PPP_STOPPING);
874
875 fsm_down(fsm);
876
877 (void)k_work_reschedule(&fsm->timer, FSM_TIMEOUT);
878 break;
879
880 default:
881 NET_DBG("[%s/%p] %s state %s (%d)", fsm->name, fsm, "Invalid",
882 ppp_state_str(fsm->state), fsm->state);
883 return NET_DROP;
884 }
885
886 (void)ppp_send_pkt(fsm, net_pkt_iface(pkt), PPP_TERMINATE_ACK, id,
887 NULL, 0);
888
889 return NET_OK;
890 }
891
fsm_recv_terminate_ack(struct ppp_fsm * fsm,uint8_t id,struct net_pkt * pkt,uint16_t length)892 static enum net_verdict fsm_recv_terminate_ack(struct ppp_fsm *fsm, uint8_t id,
893 struct net_pkt *pkt,
894 uint16_t length)
895 {
896 enum ppp_state new_state;
897
898 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
899 ppp_state_str(fsm->state), fsm->state);
900
901 switch (fsm->state) {
902 case PPP_CLOSING:
903 new_state = PPP_CLOSED;
904 goto stopped;
905
906 case PPP_OPENED:
907 fsm_down(fsm);
908
909 fsm_send_configure_req(fsm, false);
910 ppp_change_state(fsm, PPP_REQUEST_SENT);
911 break;
912
913 case PPP_STOPPING:
914 new_state = PPP_STOPPED;
915 goto stopped;
916
917 case PPP_ACK_RECEIVED:
918 ppp_change_state(fsm, PPP_REQUEST_SENT);
919 break;
920
921 default:
922 NET_DBG("[%s/%p] %s state %s (%d)", fsm->name, fsm, "Invalid",
923 ppp_state_str(fsm->state), fsm->state);
924 return NET_DROP;
925 }
926
927 return NET_OK;
928
929 stopped:
930 k_work_cancel_delayable(&fsm->timer);
931 ppp_change_state(fsm, new_state);
932
933 if (fsm->cb.finished) {
934 fsm->cb.finished(fsm);
935 }
936
937 return NET_OK;
938 }
939
fsm_recv_code_rej(struct ppp_fsm * fsm,struct net_pkt * pkt)940 static enum net_verdict fsm_recv_code_rej(struct ppp_fsm *fsm,
941 struct net_pkt *pkt)
942 {
943 uint8_t code, id;
944 int ret;
945
946 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
947 ppp_state_str(fsm->state), fsm->state);
948
949 ret = net_pkt_read_u8(pkt, &code);
950 if (ret < 0) {
951 return NET_DROP;
952 }
953
954 ret = net_pkt_read_u8(pkt, &id);
955 if (ret < 0) {
956 return NET_DROP;
957 }
958
959 NET_DBG("[%s/%p] Received Code-Rej code %d id %d", fsm->name, fsm,
960 code, id);
961
962 if (fsm->state == PPP_ACK_RECEIVED) {
963 ppp_change_state(fsm, PPP_REQUEST_SENT);
964 }
965
966 return NET_OK;
967 }
968
ppp_fsm_proto_reject(struct ppp_fsm * fsm)969 void ppp_fsm_proto_reject(struct ppp_fsm *fsm)
970 {
971 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
972 ppp_state_str(fsm->state), fsm->state);
973
974 switch (fsm->state) {
975 case PPP_ACK_RECEIVED:
976 case PPP_ACK_SENT:
977 case PPP_STOPPING:
978 case PPP_REQUEST_SENT:
979 k_work_cancel_delayable(&fsm->timer);
980 ppp_change_state(fsm, PPP_STOPPED);
981 if (fsm->cb.finished) {
982 fsm->cb.finished(fsm);
983 }
984
985 break;
986
987 case PPP_CLOSED:
988 ppp_change_state(fsm, PPP_CLOSED);
989 if (fsm->cb.finished) {
990 fsm->cb.finished(fsm);
991 }
992
993 break;
994
995 case PPP_CLOSING:
996 k_work_cancel_delayable(&fsm->timer);
997 ppp_change_state(fsm, PPP_CLOSED);
998 if (fsm->cb.finished) {
999 fsm->cb.finished(fsm);
1000 }
1001
1002 break;
1003
1004 case PPP_OPENED:
1005 terminate(fsm, PPP_STOPPING);
1006 break;
1007
1008 case PPP_STOPPED:
1009 ppp_change_state(fsm, PPP_STOPPED);
1010 if (fsm->cb.finished) {
1011 fsm->cb.finished(fsm);
1012 }
1013
1014 break;
1015
1016 default:
1017 NET_DBG("[%s/%p] %s state %s (%d)", fsm->name, fsm, "Invalid",
1018 ppp_state_str(fsm->state), fsm->state);
1019 break;
1020 }
1021 }
1022
ppp_fsm_input(struct ppp_fsm * fsm,uint16_t proto,struct net_pkt * pkt)1023 enum net_verdict ppp_fsm_input(struct ppp_fsm *fsm, uint16_t proto,
1024 struct net_pkt *pkt)
1025 {
1026 uint8_t code, id;
1027 uint16_t length;
1028 int ret;
1029 struct ppp_context *ctx = ppp_fsm_ctx(fsm);
1030
1031 ret = net_pkt_read_u8(pkt, &code);
1032 if (ret < 0) {
1033 NET_DBG("[%s/%p] Cannot read %s (pkt len %zd)",
1034 fsm->name, fsm, "code", net_pkt_get_len(pkt));
1035 return NET_DROP;
1036 }
1037
1038 ret = net_pkt_read_u8(pkt, &id);
1039 if (ret < 0) {
1040 NET_DBG("[%s/%p] Cannot read %s (pkt len %zd)",
1041 fsm->name, fsm, "id", net_pkt_get_len(pkt));
1042 return NET_DROP;
1043 }
1044
1045 ret = net_pkt_read_be16(pkt, &length);
1046 if (ret < 0) {
1047 NET_DBG("[%s/%p] Cannot read %s (pkt len %zd)",
1048 fsm->name, fsm, "length", net_pkt_get_len(pkt));
1049 return NET_DROP;
1050 }
1051
1052 if (length > ctx->lcp.my_options.mru) {
1053 NET_DBG("[%s/%p] Too long msg %d", fsm->name, fsm, length);
1054 return NET_DROP;
1055 }
1056
1057 if (fsm->state == PPP_INITIAL || fsm->state == PPP_STARTING) {
1058 NET_DBG("[%s/%p] Received %s packet in wrong state %s (%d)",
1059 fsm->name, fsm, ppp_proto2str(proto),
1060 ppp_state_str(fsm->state), fsm->state);
1061 return NET_DROP;
1062 }
1063
1064 /* Length will only contain payload/data length */
1065 length -= sizeof(code) + sizeof(id) + sizeof(length);
1066
1067 NET_DBG("[%s/%p] %s %s (%d) id %d payload len %d", fsm->name, fsm,
1068 ppp_proto2str(proto), ppp_pkt_type2str(code), code, id,
1069 length);
1070
1071 switch (code) {
1072 case PPP_CODE_REJ:
1073 return fsm_recv_code_rej(fsm, pkt);
1074
1075 case PPP_CONFIGURE_ACK:
1076 return fsm_recv_configure_ack(fsm, id, pkt, length);
1077
1078 case PPP_CONFIGURE_NACK:
1079 return fsm_recv_configure_nack_rej(fsm, code, id, pkt, length);
1080
1081 case PPP_CONFIGURE_REQ:
1082 return fsm_recv_configure_req(fsm, id, pkt, length);
1083
1084 case PPP_CONFIGURE_REJ:
1085 return fsm_recv_configure_nack_rej(fsm, code, id, pkt, length);
1086
1087 case PPP_TERMINATE_ACK:
1088 return fsm_recv_terminate_ack(fsm, id, pkt, length);
1089
1090 case PPP_TERMINATE_REQ:
1091 return fsm_recv_terminate_req(fsm, id, pkt, length);
1092
1093 default:
1094 if (fsm->cb.proto_extension) {
1095 enum net_verdict verdict;
1096
1097 verdict = fsm->cb.proto_extension(fsm, code, id, pkt);
1098 if (verdict != NET_DROP) {
1099 return verdict;
1100 }
1101 }
1102
1103 (void)ppp_send_pkt(fsm, net_pkt_iface(pkt), PPP_CODE_REJ,
1104 id, pkt, 0);
1105 }
1106
1107 return NET_DROP;
1108 }
1109
ppp_fsm_recv_protocol_rej(struct ppp_fsm * fsm,uint8_t id,struct net_pkt * pkt)1110 enum net_verdict ppp_fsm_recv_protocol_rej(struct ppp_fsm *fsm,
1111 uint8_t id,
1112 struct net_pkt *pkt)
1113 {
1114 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
1115 ppp_state_str(fsm->state), fsm->state);
1116
1117 return NET_DROP;
1118 }
1119
ppp_fsm_recv_echo_req(struct ppp_fsm * fsm,uint8_t id,struct net_pkt * pkt)1120 enum net_verdict ppp_fsm_recv_echo_req(struct ppp_fsm *fsm,
1121 uint8_t id,
1122 struct net_pkt *pkt)
1123 {
1124 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
1125 ppp_state_str(fsm->state), fsm->state);
1126
1127 (void)ppp_send_pkt(fsm, net_pkt_iface(pkt), PPP_ECHO_REPLY,
1128 id, pkt, 0);
1129
1130 return NET_OK;
1131 }
1132
ppp_fsm_recv_echo_reply(struct ppp_fsm * fsm,uint8_t id,struct net_pkt * pkt)1133 enum net_verdict ppp_fsm_recv_echo_reply(struct ppp_fsm *fsm,
1134 uint8_t id,
1135 struct net_pkt *pkt)
1136 {
1137 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
1138 ppp_state_str(fsm->state), fsm->state);
1139
1140 #if defined(CONFIG_NET_SHELL)
1141 struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
1142 lcp.fsm);
1143 if (ctx->shell.echo_reply.cb) {
1144 ctx->shell.echo_reply.cb(ctx->shell.echo_reply.user_data,
1145 ctx->shell.echo_reply.user_data_len);
1146 }
1147 #endif /* CONFIG_NET_SHELL */
1148
1149 return NET_OK;
1150 }
1151
ppp_fsm_recv_discard_req(struct ppp_fsm * fsm,uint8_t id,struct net_pkt * pkt)1152 enum net_verdict ppp_fsm_recv_discard_req(struct ppp_fsm *fsm,
1153 uint8_t id,
1154 struct net_pkt *pkt)
1155 {
1156 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
1157 ppp_state_str(fsm->state), fsm->state);
1158
1159 return NET_OK;
1160 }
1161
ppp_send_proto_rej(struct net_if * iface,struct net_pkt * pkt,uint16_t protocol)1162 void ppp_send_proto_rej(struct net_if *iface, struct net_pkt *pkt,
1163 uint16_t protocol)
1164 {
1165 uint8_t code, id;
1166 int ret;
1167
1168 ret = net_pkt_read_u8(pkt, &code);
1169 if (ret < 0) {
1170 goto quit;
1171 }
1172
1173 ret = net_pkt_read_u8(pkt, &id);
1174 if (ret < 0) {
1175 goto quit;
1176 }
1177
1178 (void)ppp_send_pkt(NULL, iface, PPP_PROTOCOL_REJ, id, pkt, 0);
1179
1180 quit:
1181 return;
1182 }
1183