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