1 /*
2  * Copyright (c) 2022 Trackunit Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/net/ppp.h>
8 #include <zephyr/sys/crc.h>
9 #include <zephyr/modem/ppp.h>
10 #include <zephyr/pm/device_runtime.h>
11 #include <string.h>
12 
13 #include "modem_workqueue.h"
14 
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(modem_ppp, CONFIG_MODEM_MODULES_LOG_LEVEL);
17 
18 #define MODEM_PPP_STATE_ATTACHED_BIT	(0)
19 #define MODEM_PPP_FRAME_TAIL_SIZE	(2)
20 
21 #define MODEM_PPP_CODE_DELIMITER	(0x7E)
22 #define MODEM_PPP_CODE_ESCAPE		(0x7D)
23 #define MODEM_PPP_VALUE_ESCAPE		(0x20)
24 
modem_ppp_fcs_init(uint8_t byte)25 static uint16_t modem_ppp_fcs_init(uint8_t byte)
26 {
27 	return crc16_ccitt(0xFFFF, &byte, 1);
28 }
29 
modem_ppp_fcs_update(uint16_t fcs,uint8_t byte)30 static uint16_t modem_ppp_fcs_update(uint16_t fcs, uint8_t byte)
31 {
32 	return crc16_ccitt(fcs, &byte, 1);
33 }
34 
modem_ppp_fcs_final(uint16_t fcs)35 static uint16_t modem_ppp_fcs_final(uint16_t fcs)
36 {
37 	return fcs ^ 0xFFFF;
38 }
39 
modem_ppp_ppp_protocol(struct net_pkt * pkt)40 static uint16_t modem_ppp_ppp_protocol(struct net_pkt *pkt)
41 {
42 	if (net_pkt_family(pkt) == NET_AF_INET) {
43 		return PPP_IP;
44 	}
45 
46 	if (net_pkt_family(pkt) == NET_AF_INET6) {
47 		return PPP_IPV6;
48 	}
49 
50 	LOG_WRN("Unsupported protocol");
51 	return 0;
52 }
53 
modem_ppp_needs_escape(uint32_t async_map,uint8_t byte)54 static bool modem_ppp_needs_escape(uint32_t async_map, uint8_t byte)
55 {
56 	uint32_t byte_bit;
57 
58 	if ((byte == MODEM_PPP_CODE_DELIMITER) || (byte == MODEM_PPP_CODE_ESCAPE)) {
59 		/* Always escaped */
60 		return true;
61 	} else if (byte >= MODEM_PPP_VALUE_ESCAPE) {
62 		/* Never escaped */
63 		return false;
64 	}
65 	byte_bit = BIT(byte);
66 	/* Escaped if required by the async control character map */
67 	return byte_bit & async_map;
68 }
69 
modem_ppp_wrap(struct modem_ppp * ppp,uint8_t * buffer,uint32_t available)70 static uint32_t modem_ppp_wrap(struct modem_ppp *ppp, uint8_t *buffer, uint32_t available)
71 {
72 	uint32_t async_map = ppp_peer_async_control_character_map(ppp->iface);
73 	uint32_t offset = 0;
74 	uint32_t remaining;
75 	uint16_t protocol;
76 	uint8_t upper;
77 	uint8_t lower;
78 	uint8_t byte;
79 
80 	while (offset < available) {
81 		remaining = available - offset;
82 
83 		switch (ppp->transmit_state) {
84 		case MODEM_PPP_TRANSMIT_STATE_SOF:
85 			if (remaining < 4) {
86 				/* Insufficient space for constant header prefix */
87 				goto end;
88 			}
89 			/* Init cursor for later phases */
90 			net_pkt_cursor_init(ppp->tx_pkt);
91 			/* 3 byte common header */
92 			buffer[offset++] = MODEM_PPP_CODE_DELIMITER;
93 			buffer[offset++] = 0xFF;
94 			buffer[offset++] = MODEM_PPP_CODE_ESCAPE;
95 			buffer[offset++] = 0x23;
96 			/* Initialise the FCS.
97 			 * This value is always the same at this point, so use the constant value.
98 			 * Equivelent to:
99 			 *   ppp->tx_pkt_fcs = modem_ppp_fcs_init(0xFF);
100 			 *   ppp->tx_pkt_fcs = modem_ppp_fcs_update(ppp->tx_pkt_fcs, 0x03);
101 			 */
102 			ARG_UNUSED(modem_ppp_fcs_init);
103 			ppp->tx_pkt_fcs = 0x3DE3;
104 			/* Next state */
105 			if (net_pkt_is_ppp(ppp->tx_pkt)) {
106 				ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_DATA;
107 			} else {
108 				ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_PROTOCOL;
109 			}
110 			break;
111 		case MODEM_PPP_TRANSMIT_STATE_PROTOCOL:
112 			/* If both protocol bytes need escaping, it could be 4 bytes */
113 			if (remaining < 4) {
114 				/* Insufficient space for protocol bytes */
115 				goto end;
116 			}
117 			/* Extract protocol bytes */
118 			protocol = modem_ppp_ppp_protocol(ppp->tx_pkt);
119 			upper = (protocol >> 8) & 0xFF;
120 			lower = (protocol >> 0) & 0xFF;
121 			/* FCS is computed without the escape/modification */
122 			ppp->tx_pkt_fcs = modem_ppp_fcs_update(ppp->tx_pkt_fcs, upper);
123 			ppp->tx_pkt_fcs = modem_ppp_fcs_update(ppp->tx_pkt_fcs, lower);
124 			/* Push protocol bytes (with required escaping) */
125 			if (modem_ppp_needs_escape(async_map, upper)) {
126 				buffer[offset++] = MODEM_PPP_CODE_ESCAPE;
127 				upper ^= MODEM_PPP_VALUE_ESCAPE;
128 			}
129 			buffer[offset++] = upper;
130 			if (modem_ppp_needs_escape(async_map, lower)) {
131 				buffer[offset++] = MODEM_PPP_CODE_ESCAPE;
132 				lower ^= MODEM_PPP_VALUE_ESCAPE;
133 			}
134 			buffer[offset++] = lower;
135 			/* Next state */
136 			ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_DATA;
137 			break;
138 		case MODEM_PPP_TRANSMIT_STATE_DATA:
139 			/* Push all data bytes into the buffer */
140 			while (net_pkt_remaining_data(ppp->tx_pkt) > 0) {
141 				/* Space available, taking into account possible escapes */
142 				if (remaining < 2) {
143 					goto end;
144 				}
145 				/* Pull next byte we're sending */
146 				(void)net_pkt_read_u8(ppp->tx_pkt, &byte);
147 				/* FCS is computed without the escape/modification */
148 				ppp->tx_pkt_fcs = modem_ppp_fcs_update(ppp->tx_pkt_fcs, byte);
149 				/* Push encoded bytes into buffer*/
150 				if (modem_ppp_needs_escape(async_map, byte)) {
151 					buffer[offset++] = MODEM_PPP_CODE_ESCAPE;
152 					byte ^= MODEM_PPP_VALUE_ESCAPE;
153 					remaining--;
154 				}
155 				buffer[offset++] = byte;
156 				remaining--;
157 			}
158 			/* Data phase finished */
159 			ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_EOF;
160 			break;
161 		case MODEM_PPP_TRANSMIT_STATE_EOF:
162 			/* If both FCS bytes need escaping, it could be 5 bytes */
163 			if (remaining < 5) {
164 				/* Insufficient space for protocol bytes */
165 				goto end;
166 			}
167 			/* Push FCS (order is [lower, upper] unlike the protocol) */
168 			ppp->tx_pkt_fcs = modem_ppp_fcs_final(ppp->tx_pkt_fcs);
169 			lower = (ppp->tx_pkt_fcs >> 0) & 0xFF;
170 			upper = (ppp->tx_pkt_fcs >> 8) & 0xFF;
171 			if (modem_ppp_needs_escape(async_map, lower)) {
172 				buffer[offset++] = MODEM_PPP_CODE_ESCAPE;
173 				lower ^= MODEM_PPP_VALUE_ESCAPE;
174 			}
175 			buffer[offset++] = lower;
176 			if (modem_ppp_needs_escape(async_map, upper)) {
177 				buffer[offset++] = MODEM_PPP_CODE_ESCAPE;
178 				upper ^= MODEM_PPP_VALUE_ESCAPE;
179 			}
180 			buffer[offset++] = upper;
181 			buffer[offset++] = MODEM_PPP_CODE_DELIMITER;
182 
183 			/* Packet has finished */
184 			ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_IDLE;
185 			goto end;
186 		default:
187 			LOG_DBG("Invalid transmit state (%d)", ppp->transmit_state);
188 			goto end;
189 		}
190 	}
191 end:
192 	return offset;
193 }
194 
modem_ppp_is_byte_expected(uint8_t byte,uint8_t expected_byte)195 static bool modem_ppp_is_byte_expected(uint8_t byte, uint8_t expected_byte)
196 {
197 	if (byte == expected_byte) {
198 		return true;
199 	}
200 	LOG_DBG("Dropping byte 0x%02hhx because 0x%02hhx was expected.", byte, expected_byte);
201 	return false;
202 }
203 
modem_ppp_process_received_byte(struct modem_ppp * ppp,uint8_t byte)204 static void modem_ppp_process_received_byte(struct modem_ppp *ppp, uint8_t byte)
205 {
206 	switch (ppp->receive_state) {
207 	case MODEM_PPP_RECEIVE_STATE_HDR_SOF:
208 		if (modem_ppp_is_byte_expected(byte, MODEM_PPP_CODE_DELIMITER)) {
209 			ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_FF;
210 		}
211 		break;
212 
213 	case MODEM_PPP_RECEIVE_STATE_HDR_FF:
214 		if (byte == MODEM_PPP_CODE_DELIMITER) {
215 			break;
216 		}
217 		if (modem_ppp_is_byte_expected(byte, 0xFF)) {
218 			ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_7D;
219 		} else {
220 			ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
221 		}
222 		break;
223 
224 	case MODEM_PPP_RECEIVE_STATE_HDR_7D:
225 		if (modem_ppp_is_byte_expected(byte, MODEM_PPP_CODE_ESCAPE)) {
226 			ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_23;
227 		} else {
228 			ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
229 		}
230 		break;
231 
232 	case MODEM_PPP_RECEIVE_STATE_HDR_23:
233 		if (modem_ppp_is_byte_expected(byte, 0x23)) {
234 			ppp->rx_pkt = net_pkt_rx_alloc_with_buffer(ppp->iface,
235 				CONFIG_MODEM_PPP_NET_BUF_FRAG_SIZE, NET_AF_UNSPEC, 0, K_NO_WAIT);
236 
237 			if (ppp->rx_pkt == NULL) {
238 				LOG_WRN("Dropped frame, no net_pkt available");
239 				ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
240 				break;
241 			}
242 
243 			LOG_DBG("Receiving PPP frame");
244 			ppp->receive_state = MODEM_PPP_RECEIVE_STATE_WRITING;
245 			net_pkt_cursor_init(ppp->rx_pkt);
246 		} else {
247 			ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
248 		}
249 
250 		break;
251 
252 	case MODEM_PPP_RECEIVE_STATE_WRITING:
253 		if (byte == MODEM_PPP_CODE_DELIMITER) {
254 			LOG_DBG("Received PPP frame (len %zu)", net_pkt_get_len(ppp->rx_pkt));
255 
256 			/* Remove FCS */
257 			net_pkt_remove_tail(ppp->rx_pkt, MODEM_PPP_FRAME_TAIL_SIZE);
258 			net_pkt_set_ppp(ppp->rx_pkt, true);
259 
260 			if (net_recv_data(ppp->iface, ppp->rx_pkt) < 0) {
261 				LOG_WRN("Net pkt could not be processed");
262 				net_pkt_unref(ppp->rx_pkt);
263 			}
264 
265 			ppp->rx_pkt = NULL;
266 			/* Skip SOF because the delimiter may be omitted for successive frames. */
267 			ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_FF;
268 			break;
269 		}
270 
271 		if (net_pkt_available_buffer(ppp->rx_pkt) == 1) {
272 			if (net_pkt_alloc_buffer(ppp->rx_pkt, CONFIG_MODEM_PPP_NET_BUF_FRAG_SIZE,
273 						 NET_AF_INET, K_NO_WAIT) < 0) {
274 				LOG_WRN("Failed to alloc buffer");
275 				net_pkt_unref(ppp->rx_pkt);
276 				ppp->rx_pkt = NULL;
277 				ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
278 				break;
279 			}
280 		}
281 
282 		if (byte == MODEM_PPP_CODE_ESCAPE) {
283 			ppp->receive_state = MODEM_PPP_RECEIVE_STATE_UNESCAPING;
284 			break;
285 		}
286 
287 		if (net_pkt_write_u8(ppp->rx_pkt, byte) < 0) {
288 			LOG_WRN("Dropped PPP frame");
289 			net_pkt_unref(ppp->rx_pkt);
290 			ppp->rx_pkt = NULL;
291 			ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
292 #if defined(CONFIG_NET_STATISTICS_PPP)
293 			ppp->stats.drop++;
294 #endif
295 		}
296 
297 		break;
298 
299 	case MODEM_PPP_RECEIVE_STATE_UNESCAPING:
300 		if (net_pkt_write_u8(ppp->rx_pkt, (byte ^ MODEM_PPP_VALUE_ESCAPE)) < 0) {
301 			LOG_WRN("Dropped PPP frame");
302 			net_pkt_unref(ppp->rx_pkt);
303 			ppp->rx_pkt = NULL;
304 			ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
305 #if defined(CONFIG_NET_STATISTICS_PPP)
306 			ppp->stats.drop++;
307 #endif
308 			break;
309 		}
310 
311 		ppp->receive_state = MODEM_PPP_RECEIVE_STATE_WRITING;
312 		break;
313 	}
314 }
315 
316 #if CONFIG_MODEM_STATS
get_transmit_buf_length(struct modem_ppp * ppp)317 static uint32_t get_transmit_buf_length(struct modem_ppp *ppp)
318 {
319 	return ring_buf_size_get(&ppp->transmit_rb);
320 }
321 
advertise_transmit_buf_stats(struct modem_ppp * ppp)322 static void advertise_transmit_buf_stats(struct modem_ppp *ppp)
323 {
324 	uint32_t length;
325 
326 	length = get_transmit_buf_length(ppp);
327 	modem_stats_buffer_advertise_length(&ppp->transmit_buf_stats, length);
328 }
329 
advertise_receive_buf_stats(struct modem_ppp * ppp,uint32_t length)330 static void advertise_receive_buf_stats(struct modem_ppp *ppp, uint32_t length)
331 {
332 	modem_stats_buffer_advertise_length(&ppp->receive_buf_stats, length);
333 }
334 #endif
335 
modem_ppp_pipe_callback(struct modem_pipe * pipe,enum modem_pipe_event event,void * user_data)336 static void modem_ppp_pipe_callback(struct modem_pipe *pipe, enum modem_pipe_event event,
337 				    void *user_data)
338 {
339 	struct modem_ppp *ppp = (struct modem_ppp *)user_data;
340 
341 	switch (event) {
342 	case MODEM_PIPE_EVENT_RECEIVE_READY:
343 		modem_work_submit(&ppp->process_work);
344 		break;
345 
346 	case MODEM_PIPE_EVENT_OPENED:
347 	case MODEM_PIPE_EVENT_TRANSMIT_IDLE:
348 		modem_work_submit(&ppp->send_work);
349 		break;
350 
351 	default:
352 		break;
353 	}
354 }
355 
modem_ppp_send_handler(struct k_work * item)356 static void modem_ppp_send_handler(struct k_work *item)
357 {
358 	struct modem_ppp *ppp = CONTAINER_OF(item, struct modem_ppp, send_work);
359 	uint8_t *reserved;
360 	uint32_t reserved_size;
361 	uint32_t pushed;
362 	int ret;
363 
364 	if (ppp->tx_pkt == NULL) {
365 		ppp->tx_pkt = k_fifo_get(&ppp->tx_pkt_fifo, K_NO_WAIT);
366 	}
367 
368 	if (ring_buf_is_empty(&ppp->transmit_rb)) {
369 		/* Reset to initial state to maximise contiguous claim */
370 		ring_buf_reset(&ppp->transmit_rb);
371 	}
372 
373 	if (ppp->tx_pkt != NULL) {
374 		/* Initialize wrap */
375 		if (ppp->transmit_state == MODEM_PPP_TRANSMIT_STATE_IDLE) {
376 			ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_SOF;
377 		}
378 
379 		/* Claim as much space as possible */
380 		reserved_size = ring_buf_put_claim(&ppp->transmit_rb, &reserved, UINT32_MAX);
381 		/* Push wrapped data into claimed buffer */
382 		pushed = modem_ppp_wrap(ppp, reserved, reserved_size);
383 		/* Limit claimed data to what was actually pushed */
384 		ring_buf_put_finish(&ppp->transmit_rb, pushed);
385 
386 		if (ppp->transmit_state == MODEM_PPP_TRANSMIT_STATE_IDLE) {
387 			net_pkt_unref(ppp->tx_pkt);
388 			ppp->tx_pkt = k_fifo_get(&ppp->tx_pkt_fifo, K_NO_WAIT);
389 		}
390 	}
391 
392 #if CONFIG_MODEM_STATS
393 	advertise_transmit_buf_stats(ppp);
394 #endif
395 
396 	while (!ring_buf_is_empty(&ppp->transmit_rb)) {
397 		reserved_size = ring_buf_get_claim(&ppp->transmit_rb, &reserved, UINT32_MAX);
398 
399 		ret = modem_pipe_transmit(ppp->pipe, reserved, reserved_size);
400 		if (ret < 0) {
401 			ring_buf_get_finish(&ppp->transmit_rb, 0);
402 			break;
403 		}
404 
405 		ring_buf_get_finish(&ppp->transmit_rb, (uint32_t)ret);
406 
407 		if (ret < reserved_size) {
408 			break;
409 		}
410 	}
411 }
412 
modem_ppp_process_handler(struct k_work * item)413 static void modem_ppp_process_handler(struct k_work *item)
414 {
415 	struct modem_ppp *ppp = CONTAINER_OF(item, struct modem_ppp, process_work);
416 	int ret;
417 
418 	ret = modem_pipe_receive(ppp->pipe, ppp->receive_buf, ppp->buf_size);
419 	if (ret < 1) {
420 		return;
421 	}
422 
423 #if CONFIG_MODEM_STATS
424 	advertise_receive_buf_stats(ppp, ret);
425 #endif
426 
427 	for (int i = 0; i < ret; i++) {
428 		modem_ppp_process_received_byte(ppp, ppp->receive_buf[i]);
429 	}
430 
431 	modem_work_submit(&ppp->process_work);
432 }
433 
modem_ppp_ppp_api_init(struct net_if * iface)434 static void modem_ppp_ppp_api_init(struct net_if *iface)
435 {
436 	const struct device *dev = net_if_get_device(iface);
437 	struct modem_ppp *ppp = (struct modem_ppp *)dev->data;
438 
439 	net_ppp_init(iface);
440 	net_if_flag_set(iface, NET_IF_NO_AUTO_START);
441 	net_if_carrier_off(iface);
442 
443 	if (ppp->init_iface != NULL) {
444 		ppp->init_iface(iface);
445 	}
446 
447 	ppp->iface = iface;
448 }
449 
modem_ppp_ppp_api_start(const struct device * dev)450 static int modem_ppp_ppp_api_start(const struct device *dev)
451 {
452 	const struct modem_ppp_config *config = (const struct modem_ppp_config *)dev->config;
453 
454 	if (config == NULL || config->dev == NULL) {
455 		return 0;
456 	}
457 
458 	return pm_device_runtime_get(config->dev);
459 }
460 
modem_ppp_ppp_api_stop(const struct device * dev)461 static int modem_ppp_ppp_api_stop(const struct device *dev)
462 {
463 	const struct modem_ppp_config *config = (const struct modem_ppp_config *)dev->config;
464 
465 	if (config == NULL || config->dev == NULL) {
466 		return 0;
467 	}
468 
469 	return pm_device_runtime_put_async(config->dev, K_NO_WAIT);
470 }
471 
modem_ppp_ppp_api_send(const struct device * dev,struct net_pkt * pkt)472 static int modem_ppp_ppp_api_send(const struct device *dev, struct net_pkt *pkt)
473 {
474 	struct modem_ppp *ppp = (struct modem_ppp *)dev->data;
475 
476 	if (atomic_test_bit(&ppp->state, MODEM_PPP_STATE_ATTACHED_BIT) == false) {
477 		return -EPERM;
478 	}
479 
480 	/* Validate packet protocol */
481 	if ((net_pkt_is_ppp(pkt) == false) && (net_pkt_family(pkt) != NET_AF_INET) &&
482 	    (net_pkt_family(pkt) != NET_AF_INET6)) {
483 		return -EPROTONOSUPPORT;
484 	}
485 
486 	/* Validate packet data length */
487 	if (((net_pkt_get_len(pkt) < 2) && (net_pkt_is_ppp(pkt) == true)) ||
488 	    ((net_pkt_get_len(pkt) < 1))) {
489 		return -ENODATA;
490 	}
491 
492 	net_pkt_ref(pkt);
493 	k_fifo_put(&ppp->tx_pkt_fifo, pkt);
494 	modem_work_submit(&ppp->send_work);
495 	return 0;
496 }
497 
498 #if defined(CONFIG_NET_STATISTICS_PPP)
modem_ppp_ppp_get_stats(const struct device * dev)499 static struct net_stats_ppp *modem_ppp_ppp_get_stats(const struct device *dev)
500 {
501 	struct modem_ppp *ppp = (struct modem_ppp *)dev->data;
502 
503 	return &ppp->stats;
504 }
505 #endif
506 
507 #if CONFIG_MODEM_STATS
get_buf_size(struct modem_ppp * ppp)508 static uint32_t get_buf_size(struct modem_ppp *ppp)
509 {
510 	return ppp->buf_size;
511 }
512 
init_buf_stats(struct modem_ppp * ppp)513 static void init_buf_stats(struct modem_ppp *ppp)
514 {
515 	char iface_name[CONFIG_MODEM_STATS_BUFFER_NAME_SIZE - sizeof("_xx")];
516 	char name[CONFIG_MODEM_STATS_BUFFER_NAME_SIZE];
517 	int ret;
518 	uint32_t size;
519 
520 	ret = net_if_get_name(ppp->iface, iface_name, sizeof(iface_name));
521 	if (ret < 0) {
522 		snprintk(iface_name, sizeof(iface_name), "ppp");
523 	}
524 
525 	size = get_buf_size(ppp);
526 	snprintk(name, sizeof(name), "%s_rx", iface_name);
527 	modem_stats_buffer_init(&ppp->receive_buf_stats, name, size);
528 	snprintk(name, sizeof(name), "%s_tx", iface_name);
529 	modem_stats_buffer_init(&ppp->transmit_buf_stats, name, size);
530 }
531 #endif
532 
533 const struct ppp_api modem_ppp_ppp_api = {
534 	.iface_api.init = modem_ppp_ppp_api_init,
535 	.start = modem_ppp_ppp_api_start,
536 	.stop = modem_ppp_ppp_api_stop,
537 	.send = modem_ppp_ppp_api_send,
538 #if defined(CONFIG_NET_STATISTICS_PPP)
539 	.get_stats = modem_ppp_ppp_get_stats,
540 #endif
541 };
542 
modem_ppp_attach(struct modem_ppp * ppp,struct modem_pipe * pipe)543 int modem_ppp_attach(struct modem_ppp *ppp, struct modem_pipe *pipe)
544 {
545 	if (atomic_test_bit(&ppp->state, MODEM_PPP_STATE_ATTACHED_BIT) == true) {
546 		return 0;
547 	}
548 
549 	ppp->pipe = pipe;
550 	modem_pipe_attach(pipe, modem_ppp_pipe_callback, ppp);
551 
552 	atomic_set_bit(&ppp->state, MODEM_PPP_STATE_ATTACHED_BIT);
553 	return 0;
554 }
555 
modem_ppp_get_iface(struct modem_ppp * ppp)556 struct net_if *modem_ppp_get_iface(struct modem_ppp *ppp)
557 {
558 	return ppp->iface;
559 }
560 
modem_ppp_release(struct modem_ppp * ppp)561 void modem_ppp_release(struct modem_ppp *ppp)
562 {
563 	struct k_work_sync sync;
564 	struct net_pkt *pkt;
565 
566 	if (atomic_test_and_clear_bit(&ppp->state, MODEM_PPP_STATE_ATTACHED_BIT) == false) {
567 		return;
568 	}
569 
570 	modem_pipe_release(ppp->pipe);
571 	k_work_cancel_sync(&ppp->send_work, &sync);
572 	k_work_cancel_sync(&ppp->process_work, &sync);
573 	ppp->pipe = NULL;
574 	ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
575 
576 	if (ppp->rx_pkt != NULL) {
577 		net_pkt_unref(ppp->rx_pkt);
578 		ppp->rx_pkt = NULL;
579 	}
580 
581 	ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_IDLE;
582 
583 	if (ppp->tx_pkt != NULL) {
584 		net_pkt_unref(ppp->tx_pkt);
585 		ppp->tx_pkt = NULL;
586 	}
587 
588 	while (1) {
589 		pkt = k_fifo_get(&ppp->tx_pkt_fifo, K_NO_WAIT);
590 		if (pkt == NULL) {
591 			break;
592 		}
593 
594 		net_pkt_unref(pkt);
595 	}
596 }
597 
modem_ppp_init_internal(const struct device * dev)598 int modem_ppp_init_internal(const struct device *dev)
599 {
600 	struct modem_ppp *ppp = (struct modem_ppp *)dev->data;
601 
602 	atomic_set(&ppp->state, 0);
603 	ring_buf_init(&ppp->transmit_rb, ppp->buf_size, ppp->transmit_buf);
604 	k_work_init(&ppp->send_work, modem_ppp_send_handler);
605 	k_work_init(&ppp->process_work, modem_ppp_process_handler);
606 	k_fifo_init(&ppp->tx_pkt_fifo);
607 
608 #if CONFIG_MODEM_STATS
609 	init_buf_stats(ppp);
610 #endif
611 	return 0;
612 }
613