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