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/random.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 (!net_if_is_carrier_ok(iface)) {
395 return -ENETDOWN;
396 }
397
398 if (fsm) {
399 protocol = fsm->protocol;
400 }
401
402 switch (type) {
403 case PPP_CODE_REJ: {
404 struct ppp_context *ctx = ppp_fsm_ctx(fsm);
405
406 len = net_pkt_get_len(req_pkt);
407 len = MIN(len, ctx->lcp.my_options.mru);
408 break;
409 }
410
411 case PPP_CONFIGURE_ACK:
412 case PPP_CONFIGURE_NACK:
413 case PPP_CONFIGURE_REJ:
414 case PPP_CONFIGURE_REQ:
415 pkt = data;
416 /* 2 + 1 + 1 (configure-[req|ack|nack|rej]) +
417 * data_len (options)
418 */
419 len = sizeof(ppp) + data_len;
420 break;
421
422 case PPP_DISCARD_REQ:
423 break;
424
425 case PPP_ECHO_REQ:
426 len = sizeof(ppp) + sizeof(uint32_t) + data_len;
427 break;
428
429 case PPP_ECHO_REPLY:
430 len = sizeof(ppp) + net_pkt_remaining_data(req_pkt);
431 break;
432
433 case PPP_PROTOCOL_REJ:
434 len = sizeof(ppp) + sizeof(uint16_t) +
435 net_pkt_remaining_data(req_pkt);
436 protocol = PPP_LCP;
437 break;
438
439 case PPP_TERMINATE_REQ:
440 case PPP_TERMINATE_ACK:
441 len = sizeof(ppp);
442 break;
443
444 default:
445 break;
446 }
447
448 if (len < sizeof(ppp)) {
449 return -EINVAL;
450 }
451
452 ppp.code = type;
453 ppp.id = id;
454 ppp.length = htons(len);
455
456 if (!pkt) {
457 pkt = net_pkt_alloc_with_buffer(iface,
458 sizeof(uint16_t) + len,
459 AF_UNSPEC, 0,
460 PPP_BUF_ALLOC_TIMEOUT);
461 if (!pkt) {
462 goto out_of_mem;
463 }
464 } else {
465 struct net_buf *buf;
466
467 buf = net_pkt_get_reserve_tx_data(sizeof(uint16_t) + len,
468 PPP_BUF_ALLOC_TIMEOUT);
469 if (!buf) {
470 LOG_ERR("failed to allocate buffer");
471 goto out_of_mem;
472 }
473
474 net_pkt_frag_insert(pkt, buf);
475 net_pkt_cursor_init(pkt);
476 }
477
478 ret = net_pkt_write_be16(pkt, protocol);
479 if (ret < 0) {
480 goto out_of_mem;
481 }
482
483 ret = net_pkt_write(pkt, &ppp, sizeof(ppp));
484 if (ret < 0) {
485 goto out_of_mem;
486 }
487
488 if (type == PPP_CODE_REJ) {
489 if (!req_pkt) {
490 goto out_of_mem;
491 }
492
493 net_pkt_cursor_init(req_pkt);
494 net_pkt_copy(pkt, req_pkt, len);
495
496 } else if (type == PPP_ECHO_REQ) {
497 struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
498 lcp.fsm);
499 if (ctx->lcp.magic) {
500 ctx->lcp.magic = sys_rand32_get();
501 }
502
503 ret = net_pkt_write_be32(pkt, ctx->lcp.magic);
504 if (ret < 0) {
505 goto out_of_mem;
506 }
507
508 data_len = MIN(data_len, ctx->lcp.my_options.mru);
509 if (data_len > 0) {
510 if (data_len == sizeof(uint32_t)) {
511 ret = net_pkt_write_be32(pkt,
512 POINTER_TO_UINT(data));
513 } else {
514 ret = net_pkt_write(pkt, data, data_len);
515 }
516
517 if (ret < 0) {
518 goto out_of_mem;
519 }
520 }
521 } else if (type == PPP_ECHO_REPLY) {
522 net_pkt_copy(pkt, req_pkt, len);
523 } else if (type == PPP_PROTOCOL_REJ) {
524 net_pkt_cursor_init(req_pkt);
525 net_pkt_copy(pkt, req_pkt, len);
526 }
527
528 NET_DBG("[%s/%p] Sending %zd bytes pkt %p (options len %d)",
529 fsm ? fsm->name : "?", fsm, net_pkt_get_len(pkt), pkt,
530 data_len);
531
532 net_pkt_set_ppp(pkt, true);
533
534 if (fsm) {
535 /* Do not call net_send_data() directly in order to make this
536 * thread run before the sending happens. If we call the
537 * net_send_data() from this thread, then in fast link (like
538 * when running inside QEMU) the reply might arrive before we
539 * have returned from this function. That is bad because the
540 * fsm would be in wrong state and the received pkt is dropped.
541 */
542 ppp_queue_pkt(pkt);
543 } else {
544 ret = net_send_data(pkt);
545 if (ret < 0) {
546 net_pkt_unref(pkt);
547 }
548 }
549
550 return 0;
551
552 out_of_mem:
553 if (pkt) {
554 net_pkt_unref(pkt);
555 }
556
557 return -ENOMEM;
558 }
559
fsm_recv_configure_req(struct ppp_fsm * fsm,uint8_t id,struct net_pkt * pkt,uint16_t remaining_len)560 static enum net_verdict fsm_recv_configure_req(struct ppp_fsm *fsm,
561 uint8_t id,
562 struct net_pkt *pkt,
563 uint16_t remaining_len)
564 {
565 struct net_pkt *out = NULL;
566 int len = 0;
567 enum ppp_packet_type code;
568
569 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
570 ppp_state_str(fsm->state), fsm->state);
571
572 switch (fsm->state) {
573 case PPP_ACK_SENT:
574 case PPP_ACK_RECEIVED:
575 break;
576
577 case PPP_CLOSED:
578 (void)ppp_send_pkt(fsm, net_pkt_iface(pkt), PPP_TERMINATE_ACK,
579 id, NULL, 0);
580 return NET_OK;
581
582 case PPP_CLOSING:
583 case PPP_STOPPING:
584 return NET_OK;
585
586 case PPP_OPENED:
587 fsm_down(fsm);
588
589 fsm_send_configure_req(fsm, false);
590 ppp_change_state(fsm, PPP_REQUEST_SENT);
591 break;
592
593 case PPP_REQUEST_SENT:
594 /* Received request while waiting ACK */
595 break;
596
597 case PPP_STOPPED:
598 fsm_send_configure_req(fsm, false);
599 ppp_change_state(fsm, PPP_REQUEST_SENT);
600 break;
601
602 default:
603 NET_DBG("[%s/%p] %s state %s (%d)", fsm->name, fsm, "Invalid",
604 ppp_state_str(fsm->state), fsm->state);
605 return NET_DROP;
606 }
607
608 out = net_pkt_alloc_with_buffer(net_pkt_iface(pkt),
609 sizeof(uint16_t) + sizeof(uint16_t) +
610 sizeof(uint8_t) + sizeof(uint8_t) +
611 remaining_len,
612 AF_UNSPEC, 0, PPP_BUF_ALLOC_TIMEOUT);
613 if (!out) {
614 return NET_DROP;
615 }
616
617 net_pkt_cursor_init(out);
618
619 if (fsm->cb.config_info_req) {
620 int ret;
621
622 ret = fsm->cb.config_info_req(fsm, pkt, remaining_len, out);
623 if (ret < 0) {
624 goto unref_out_pkt;
625 }
626
627 if (fsm->nack_loops >= MAX_NACK_LOOPS &&
628 ret == PPP_CONFIGURE_NACK) {
629 ret = PPP_CONFIGURE_REJ;
630 }
631
632 code = ret;
633 len = net_pkt_get_len(out);
634 } else if (remaining_len) {
635 code = PPP_CONFIGURE_REJ;
636
637 net_pkt_copy(out, pkt, remaining_len);
638 len = remaining_len;
639 } else {
640 code = PPP_CONFIGURE_ACK;
641 }
642
643 NET_DBG("[%s/%p] Sending %s (%d) id %d to peer while in %s (%d)",
644 fsm->name, fsm, ppp_pkt_type2str(code), code, id,
645 ppp_state_str(fsm->state), fsm->state);
646
647 (void)ppp_send_pkt(fsm, NULL, code, id, out, len);
648
649 if (code == PPP_CONFIGURE_ACK) {
650 if (fsm->state == PPP_ACK_RECEIVED) {
651 k_work_cancel_delayable(&fsm->timer);
652
653 ppp_change_state(fsm, PPP_OPENED);
654
655 if (fsm->cb.up) {
656 fsm->cb.up(fsm);
657 }
658 } else {
659 ppp_change_state(fsm, PPP_ACK_SENT);
660 }
661
662 fsm->nack_loops = 0;
663 } else {
664 if (fsm->state != PPP_ACK_RECEIVED) {
665 ppp_change_state(fsm, PPP_REQUEST_SENT);
666 }
667
668 if (code == PPP_CONFIGURE_NACK) {
669 fsm->nack_loops++;
670 }
671 }
672
673 return NET_OK;
674
675 unref_out_pkt:
676 net_pkt_unref(out);
677
678 return NET_DROP;
679 }
680
fsm_recv_configure_ack(struct ppp_fsm * fsm,uint8_t id,struct net_pkt * pkt,uint16_t remaining_len)681 static enum net_verdict fsm_recv_configure_ack(struct ppp_fsm *fsm, uint8_t id,
682 struct net_pkt *pkt,
683 uint16_t remaining_len)
684 {
685 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
686 ppp_state_str(fsm->state), fsm->state);
687
688 if (id != fsm->req_id || fsm->ack_received) {
689 return NET_DROP;
690 }
691
692 if (fsm->cb.config_info_ack) {
693 if (fsm->cb.config_info_ack(fsm, pkt, remaining_len) < 0) {
694 NET_DBG("[%s/%p] %s %s received", fsm->name, fsm,
695 "Invalid",
696 ppp_pkt_type2str(PPP_CONFIGURE_ACK));
697 return NET_DROP;
698 }
699 }
700
701 fsm->ack_received = true;
702 fsm->recv_nack_loops = 0;
703
704 switch (fsm->state) {
705 case PPP_ACK_RECEIVED:
706 k_work_cancel_delayable(&fsm->timer);
707 fsm_send_configure_req(fsm, false);
708 ppp_change_state(fsm, PPP_REQUEST_SENT);
709 break;
710
711 case PPP_ACK_SENT:
712 k_work_cancel_delayable(&fsm->timer);
713 ppp_change_state(fsm, PPP_OPENED);
714 fsm->retransmits = MAX_CONFIGURE_REQ;
715 if (fsm->cb.up) {
716 fsm->cb.up(fsm);
717 }
718
719 break;
720
721 case PPP_CLOSED:
722 case PPP_STOPPED:
723 (void)ppp_send_pkt(fsm, net_pkt_iface(pkt), PPP_TERMINATE_ACK,
724 id, NULL, 0);
725 break;
726
727 case PPP_OPENED:
728 fsm_down(fsm);
729
730 fsm_send_configure_req(fsm, false);
731 ppp_change_state(fsm, PPP_REQUEST_SENT);
732 break;
733
734 case PPP_REQUEST_SENT:
735 ppp_change_state(fsm, PPP_ACK_RECEIVED);
736 fsm->retransmits = MAX_CONFIGURE_REQ;
737 break;
738
739 default:
740 NET_DBG("[%s/%p] %s state %s (%d)", fsm->name, fsm, "Invalid",
741 ppp_state_str(fsm->state), fsm->state);
742 return NET_DROP;
743 }
744
745 return NET_OK;
746 }
747
fsm_recv_configure_nack_rej(struct ppp_fsm * fsm,enum ppp_packet_type code,uint8_t id,struct net_pkt * pkt,uint16_t length)748 static enum net_verdict fsm_recv_configure_nack_rej(struct ppp_fsm *fsm,
749 enum ppp_packet_type code,
750 uint8_t id,
751 struct net_pkt *pkt,
752 uint16_t length)
753 {
754 bool ret = false;
755
756 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
757 ppp_state_str(fsm->state), fsm->state);
758
759 if (id != fsm->req_id || fsm->ack_received) {
760 return NET_DROP;
761 }
762
763 if (code == PPP_CONFIGURE_NACK) {
764 bool rejected = false;
765
766 fsm->recv_nack_loops++;
767
768 if (fsm->recv_nack_loops >= MAX_NACK_LOOPS) {
769 rejected = true;
770 }
771
772 if (fsm->cb.config_info_nack) {
773 int err;
774
775 err = fsm->cb.config_info_nack(fsm, pkt, length,
776 rejected);
777 if (err < 0) {
778 NET_DBG("[%s/%p] %s failed (%d)",
779 fsm->name, fsm, "Nack", err);
780 } else {
781 ret = true;
782 }
783 }
784
785 if (!ret) {
786 NET_DBG("[%s/%p] %s %s (id %d)", fsm->name, fsm,
787 "Invalid", ppp_pkt_type2str(code), id);
788 return NET_DROP;
789 }
790 } else {
791 fsm->recv_nack_loops = 0;
792
793 if (fsm->cb.config_info_rej) {
794 int err;
795
796 err = fsm->cb.config_info_rej(fsm, pkt, length);
797 if (err < 0) {
798 NET_DBG("[%s/%p] %s failed (%d)",
799 fsm->name, fsm, "Reject", err);
800 } else {
801 ret = true;
802 }
803 }
804
805 if (!ret) {
806 NET_DBG("[%s/%p] %s %s (id %d)", fsm->name, fsm,
807 "Invalid", ppp_pkt_type2str(code), id);
808 return NET_DROP;
809 }
810 }
811
812 fsm->ack_received = true;
813
814 switch (fsm->state) {
815 case PPP_ACK_RECEIVED:
816 k_work_cancel_delayable(&fsm->timer);
817 fsm_send_configure_req(fsm, false);
818 ppp_change_state(fsm, PPP_REQUEST_SENT);
819 break;
820
821 case PPP_ACK_SENT:
822 case PPP_REQUEST_SENT:
823 k_work_cancel_delayable(&fsm->timer);
824 fsm_send_configure_req(fsm, false);
825 break;
826
827 case PPP_CLOSED:
828 case PPP_STOPPED:
829 (void)ppp_send_pkt(fsm, net_pkt_iface(pkt), PPP_TERMINATE_ACK,
830 id, NULL, 0);
831 break;
832
833 case PPP_OPENED:
834 fsm_down(fsm);
835
836 fsm_send_configure_req(fsm, false);
837 ppp_change_state(fsm, PPP_REQUEST_SENT);
838 break;
839
840 default:
841 NET_DBG("[%s/%p] %s state %s (%d)", fsm->name, fsm, "Invalid",
842 ppp_state_str(fsm->state), fsm->state);
843 return NET_DROP;
844 }
845
846 return NET_OK;
847 }
848
fsm_recv_terminate_req(struct ppp_fsm * fsm,uint8_t id,struct net_pkt * pkt,uint16_t length)849 static enum net_verdict fsm_recv_terminate_req(struct ppp_fsm *fsm, uint8_t id,
850 struct net_pkt *pkt,
851 uint16_t length)
852 {
853 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
854 ppp_state_str(fsm->state), fsm->state);
855
856 switch (fsm->state) {
857 case PPP_ACK_RECEIVED:
858 case PPP_ACK_SENT:
859 ppp_change_state(fsm, PPP_REQUEST_SENT);
860 break;
861
862 case PPP_OPENED:
863 if (length > 0) {
864 net_pkt_read(pkt, fsm->terminate_reason,
865 MIN(length,
866 sizeof(fsm->terminate_reason) - 1));
867
868 NET_DBG("[%s/%p] %s (%s)",
869 fsm->name, fsm, "Terminated by peer",
870 fsm->terminate_reason);
871 } else {
872 NET_DBG("[%s/%p] Terminated by peer",
873 fsm->name, fsm);
874 }
875
876 fsm->retransmits = 0;
877 ppp_change_state(fsm, PPP_STOPPING);
878
879 fsm_down(fsm);
880
881 (void)k_work_reschedule(&fsm->timer, FSM_TIMEOUT);
882 break;
883
884 default:
885 NET_DBG("[%s/%p] %s state %s (%d)", fsm->name, fsm, "Invalid",
886 ppp_state_str(fsm->state), fsm->state);
887 return NET_DROP;
888 }
889
890 (void)ppp_send_pkt(fsm, net_pkt_iface(pkt), PPP_TERMINATE_ACK, id,
891 NULL, 0);
892
893 return NET_OK;
894 }
895
fsm_recv_terminate_ack(struct ppp_fsm * fsm,uint8_t id,struct net_pkt * pkt,uint16_t length)896 static enum net_verdict fsm_recv_terminate_ack(struct ppp_fsm *fsm, uint8_t id,
897 struct net_pkt *pkt,
898 uint16_t length)
899 {
900 enum ppp_state new_state;
901
902 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
903 ppp_state_str(fsm->state), fsm->state);
904
905 switch (fsm->state) {
906 case PPP_CLOSING:
907 new_state = PPP_CLOSED;
908 goto stopped;
909
910 case PPP_OPENED:
911 fsm_down(fsm);
912
913 fsm_send_configure_req(fsm, false);
914 ppp_change_state(fsm, PPP_REQUEST_SENT);
915 break;
916
917 case PPP_STOPPING:
918 new_state = PPP_STOPPED;
919 goto stopped;
920
921 case PPP_ACK_RECEIVED:
922 ppp_change_state(fsm, PPP_REQUEST_SENT);
923 break;
924
925 default:
926 NET_DBG("[%s/%p] %s state %s (%d)", fsm->name, fsm, "Invalid",
927 ppp_state_str(fsm->state), fsm->state);
928 return NET_DROP;
929 }
930
931 return NET_OK;
932
933 stopped:
934 k_work_cancel_delayable(&fsm->timer);
935 ppp_change_state(fsm, new_state);
936
937 if (fsm->cb.finished) {
938 fsm->cb.finished(fsm);
939 }
940
941 return NET_OK;
942 }
943
fsm_recv_code_rej(struct ppp_fsm * fsm,struct net_pkt * pkt)944 static enum net_verdict fsm_recv_code_rej(struct ppp_fsm *fsm,
945 struct net_pkt *pkt)
946 {
947 uint8_t code, id;
948 int ret;
949
950 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
951 ppp_state_str(fsm->state), fsm->state);
952
953 ret = net_pkt_read_u8(pkt, &code);
954 if (ret < 0) {
955 return NET_DROP;
956 }
957
958 ret = net_pkt_read_u8(pkt, &id);
959 if (ret < 0) {
960 return NET_DROP;
961 }
962
963 NET_DBG("[%s/%p] Received Code-Rej code %d id %d", fsm->name, fsm,
964 code, id);
965
966 if (fsm->state == PPP_ACK_RECEIVED) {
967 ppp_change_state(fsm, PPP_REQUEST_SENT);
968 }
969
970 return NET_OK;
971 }
972
ppp_fsm_proto_reject(struct ppp_fsm * fsm)973 void ppp_fsm_proto_reject(struct ppp_fsm *fsm)
974 {
975 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
976 ppp_state_str(fsm->state), fsm->state);
977
978 switch (fsm->state) {
979 case PPP_ACK_RECEIVED:
980 case PPP_ACK_SENT:
981 case PPP_STOPPING:
982 case PPP_REQUEST_SENT:
983 k_work_cancel_delayable(&fsm->timer);
984 ppp_change_state(fsm, PPP_STOPPED);
985 if (fsm->cb.finished) {
986 fsm->cb.finished(fsm);
987 }
988
989 break;
990
991 case PPP_CLOSED:
992 ppp_change_state(fsm, PPP_CLOSED);
993 if (fsm->cb.finished) {
994 fsm->cb.finished(fsm);
995 }
996
997 break;
998
999 case PPP_CLOSING:
1000 k_work_cancel_delayable(&fsm->timer);
1001 ppp_change_state(fsm, PPP_CLOSED);
1002 if (fsm->cb.finished) {
1003 fsm->cb.finished(fsm);
1004 }
1005
1006 break;
1007
1008 case PPP_OPENED:
1009 terminate(fsm, PPP_STOPPING);
1010 break;
1011
1012 case PPP_STOPPED:
1013 ppp_change_state(fsm, PPP_STOPPED);
1014 if (fsm->cb.finished) {
1015 fsm->cb.finished(fsm);
1016 }
1017
1018 break;
1019
1020 default:
1021 NET_DBG("[%s/%p] %s state %s (%d)", fsm->name, fsm, "Invalid",
1022 ppp_state_str(fsm->state), fsm->state);
1023 break;
1024 }
1025 }
1026
ppp_fsm_input(struct ppp_fsm * fsm,uint16_t proto,struct net_pkt * pkt)1027 enum net_verdict ppp_fsm_input(struct ppp_fsm *fsm, uint16_t proto,
1028 struct net_pkt *pkt)
1029 {
1030 uint8_t code, id;
1031 uint16_t length;
1032 int ret;
1033 struct ppp_context *ctx = ppp_fsm_ctx(fsm);
1034
1035 ret = net_pkt_read_u8(pkt, &code);
1036 if (ret < 0) {
1037 NET_DBG("[%s/%p] Cannot read %s (pkt len %zd)",
1038 fsm->name, fsm, "code", net_pkt_get_len(pkt));
1039 return NET_DROP;
1040 }
1041
1042 ret = net_pkt_read_u8(pkt, &id);
1043 if (ret < 0) {
1044 NET_DBG("[%s/%p] Cannot read %s (pkt len %zd)",
1045 fsm->name, fsm, "id", net_pkt_get_len(pkt));
1046 return NET_DROP;
1047 }
1048
1049 ret = net_pkt_read_be16(pkt, &length);
1050 if (ret < 0) {
1051 NET_DBG("[%s/%p] Cannot read %s (pkt len %zd)",
1052 fsm->name, fsm, "length", net_pkt_get_len(pkt));
1053 return NET_DROP;
1054 }
1055
1056 if (length > ctx->lcp.my_options.mru) {
1057 NET_DBG("[%s/%p] Too long msg %d", fsm->name, fsm, length);
1058 return NET_DROP;
1059 }
1060
1061 if (fsm->state == PPP_INITIAL || fsm->state == PPP_STARTING) {
1062 NET_DBG("[%s/%p] Received %s packet in wrong state %s (%d)",
1063 fsm->name, fsm, ppp_proto2str(proto),
1064 ppp_state_str(fsm->state), fsm->state);
1065 return NET_DROP;
1066 }
1067
1068 /* Length will only contain payload/data length */
1069 length -= sizeof(code) + sizeof(id) + sizeof(length);
1070
1071 NET_DBG("[%s/%p] %s %s (%d) id %d payload len %d", fsm->name, fsm,
1072 ppp_proto2str(proto), ppp_pkt_type2str(code), code, id,
1073 length);
1074
1075 switch (code) {
1076 case PPP_CODE_REJ:
1077 return fsm_recv_code_rej(fsm, pkt);
1078
1079 case PPP_CONFIGURE_ACK:
1080 return fsm_recv_configure_ack(fsm, id, pkt, length);
1081
1082 case PPP_CONFIGURE_NACK:
1083 return fsm_recv_configure_nack_rej(fsm, code, id, pkt, length);
1084
1085 case PPP_CONFIGURE_REQ:
1086 return fsm_recv_configure_req(fsm, id, pkt, length);
1087
1088 case PPP_CONFIGURE_REJ:
1089 return fsm_recv_configure_nack_rej(fsm, code, id, pkt, length);
1090
1091 case PPP_TERMINATE_ACK:
1092 return fsm_recv_terminate_ack(fsm, id, pkt, length);
1093
1094 case PPP_TERMINATE_REQ:
1095 return fsm_recv_terminate_req(fsm, id, pkt, length);
1096
1097 default:
1098 if (fsm->cb.proto_extension) {
1099 enum net_verdict verdict;
1100
1101 verdict = fsm->cb.proto_extension(fsm, code, id, pkt);
1102 if (verdict != NET_DROP) {
1103 return verdict;
1104 }
1105 }
1106
1107 (void)ppp_send_pkt(fsm, net_pkt_iface(pkt), PPP_CODE_REJ,
1108 id, pkt, 0);
1109 }
1110
1111 return NET_DROP;
1112 }
1113
ppp_fsm_recv_protocol_rej(struct ppp_fsm * fsm,uint8_t id,struct net_pkt * pkt)1114 enum net_verdict ppp_fsm_recv_protocol_rej(struct ppp_fsm *fsm,
1115 uint8_t id,
1116 struct net_pkt *pkt)
1117 {
1118 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
1119 ppp_state_str(fsm->state), fsm->state);
1120
1121 return NET_DROP;
1122 }
1123
ppp_fsm_recv_echo_req(struct ppp_fsm * fsm,uint8_t id,struct net_pkt * pkt)1124 enum net_verdict ppp_fsm_recv_echo_req(struct ppp_fsm *fsm,
1125 uint8_t id,
1126 struct net_pkt *pkt)
1127 {
1128 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
1129 ppp_state_str(fsm->state), fsm->state);
1130
1131 (void)ppp_send_pkt(fsm, net_pkt_iface(pkt), PPP_ECHO_REPLY,
1132 id, pkt, 0);
1133
1134 return NET_OK;
1135 }
1136
ppp_fsm_recv_echo_reply(struct ppp_fsm * fsm,uint8_t id,struct net_pkt * pkt)1137 enum net_verdict ppp_fsm_recv_echo_reply(struct ppp_fsm *fsm,
1138 uint8_t id,
1139 struct net_pkt *pkt)
1140 {
1141 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
1142 ppp_state_str(fsm->state), fsm->state);
1143
1144 #if defined(CONFIG_NET_SHELL)
1145 struct ppp_context *ctx = CONTAINER_OF(fsm, struct ppp_context,
1146 lcp.fsm);
1147 if (ctx->shell.echo_reply.cb) {
1148 ctx->shell.echo_reply.cb(ctx->shell.echo_reply.user_data,
1149 ctx->shell.echo_reply.user_data_len);
1150 }
1151 #endif /* CONFIG_NET_SHELL */
1152
1153 return NET_OK;
1154 }
1155
ppp_fsm_recv_discard_req(struct ppp_fsm * fsm,uint8_t id,struct net_pkt * pkt)1156 enum net_verdict ppp_fsm_recv_discard_req(struct ppp_fsm *fsm,
1157 uint8_t id,
1158 struct net_pkt *pkt)
1159 {
1160 NET_DBG("[%s/%p] Current state %s (%d)", fsm->name, fsm,
1161 ppp_state_str(fsm->state), fsm->state);
1162
1163 return NET_OK;
1164 }
1165
ppp_send_proto_rej(struct net_if * iface,struct net_pkt * pkt,uint16_t protocol)1166 void ppp_send_proto_rej(struct net_if *iface, struct net_pkt *pkt,
1167 uint16_t protocol)
1168 {
1169 uint8_t code, id;
1170 int ret;
1171
1172 ret = net_pkt_read_u8(pkt, &code);
1173 if (ret < 0) {
1174 goto quit;
1175 }
1176
1177 ret = net_pkt_read_u8(pkt, &id);
1178 if (ret < 0) {
1179 goto quit;
1180 }
1181
1182 (void)ppp_send_pkt(NULL, iface, PPP_PROTOCOL_REJ, id, pkt, 0);
1183
1184 quit:
1185 return;
1186 }
1187