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 <string.h>
11
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(modem_ppp, CONFIG_MODEM_MODULES_LOG_LEVEL);
14
15 #define MODEM_PPP_STATE_ATTACHED_BIT (0)
16 #define MODEM_PPP_FRAME_TAIL_SIZE (2)
17
18 #define MODEM_PPP_CODE_DELIMITER (0x7E)
19 #define MODEM_PPP_CODE_ESCAPE (0x7D)
20 #define MODEM_PPP_VALUE_ESCAPE (0x20)
21
modem_ppp_fcs_init(uint8_t byte)22 static uint16_t modem_ppp_fcs_init(uint8_t byte)
23 {
24 return crc16_ccitt(0xFFFF, &byte, 1);
25 }
26
modem_ppp_fcs_update(uint16_t fcs,uint8_t byte)27 static uint16_t modem_ppp_fcs_update(uint16_t fcs, uint8_t byte)
28 {
29 return crc16_ccitt(fcs, &byte, 1);
30 }
31
modem_ppp_fcs_final(uint16_t fcs)32 static uint16_t modem_ppp_fcs_final(uint16_t fcs)
33 {
34 return fcs ^ 0xFFFF;
35 }
36
modem_ppp_ppp_protocol(struct net_pkt * pkt)37 static uint16_t modem_ppp_ppp_protocol(struct net_pkt *pkt)
38 {
39 if (net_pkt_family(pkt) == AF_INET) {
40 return PPP_IP;
41 }
42
43 if (net_pkt_family(pkt) == AF_INET6) {
44 return PPP_IPV6;
45 }
46
47 LOG_WRN("Unsupported protocol");
48 return 0;
49 }
50
modem_ppp_wrap_net_pkt_byte(struct modem_ppp * ppp)51 static uint8_t modem_ppp_wrap_net_pkt_byte(struct modem_ppp *ppp)
52 {
53 uint8_t byte;
54
55 switch (ppp->transmit_state) {
56 case MODEM_PPP_TRANSMIT_STATE_IDLE:
57 LOG_WRN("Invalid transmit state");
58 return 0;
59
60 /* Writing header */
61 case MODEM_PPP_TRANSMIT_STATE_SOF:
62 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_HDR_FF;
63 return MODEM_PPP_CODE_DELIMITER;
64
65 case MODEM_PPP_TRANSMIT_STATE_HDR_FF:
66 net_pkt_cursor_init(ppp->tx_pkt);
67 ppp->tx_pkt_fcs = modem_ppp_fcs_init(0xFF);
68 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_HDR_7D;
69 return 0xFF;
70
71 case MODEM_PPP_TRANSMIT_STATE_HDR_7D:
72 ppp->tx_pkt_fcs = modem_ppp_fcs_update(ppp->tx_pkt_fcs, 0x03);
73 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_HDR_23;
74 return MODEM_PPP_CODE_ESCAPE;
75
76 case MODEM_PPP_TRANSMIT_STATE_HDR_23:
77 if (net_pkt_is_ppp(ppp->tx_pkt) == true) {
78 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_DATA;
79 } else {
80 ppp->tx_pkt_protocol = modem_ppp_ppp_protocol(ppp->tx_pkt);
81 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_PROTOCOL_HIGH;
82 }
83
84 return 0x23;
85
86 /* Writing protocol */
87 case MODEM_PPP_TRANSMIT_STATE_PROTOCOL_HIGH:
88 byte = (ppp->tx_pkt_protocol >> 8) & 0xFF;
89 ppp->tx_pkt_fcs = modem_ppp_fcs_update(ppp->tx_pkt_fcs, byte);
90
91 if ((byte == MODEM_PPP_CODE_DELIMITER) || (byte == MODEM_PPP_CODE_ESCAPE) ||
92 (byte < MODEM_PPP_VALUE_ESCAPE)) {
93 ppp->tx_pkt_escaped = byte ^ MODEM_PPP_VALUE_ESCAPE;
94 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_ESCAPING_PROTOCOL_HIGH;
95 return MODEM_PPP_CODE_ESCAPE;
96 }
97
98 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_PROTOCOL_LOW;
99 return byte;
100
101 case MODEM_PPP_TRANSMIT_STATE_ESCAPING_PROTOCOL_HIGH:
102 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_PROTOCOL_LOW;
103 return ppp->tx_pkt_escaped;
104
105 case MODEM_PPP_TRANSMIT_STATE_PROTOCOL_LOW:
106 byte = ppp->tx_pkt_protocol & 0xFF;
107 ppp->tx_pkt_fcs = modem_ppp_fcs_update(ppp->tx_pkt_fcs, byte);
108
109 if ((byte == MODEM_PPP_CODE_DELIMITER) || (byte == MODEM_PPP_CODE_ESCAPE) ||
110 (byte < MODEM_PPP_VALUE_ESCAPE)) {
111 ppp->tx_pkt_escaped = byte ^ MODEM_PPP_VALUE_ESCAPE;
112 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_ESCAPING_PROTOCOL_LOW;
113 return MODEM_PPP_CODE_ESCAPE;
114 }
115
116 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_DATA;
117 return byte;
118
119 case MODEM_PPP_TRANSMIT_STATE_ESCAPING_PROTOCOL_LOW:
120 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_DATA;
121 return ppp->tx_pkt_escaped;
122
123 /* Writing data */
124 case MODEM_PPP_TRANSMIT_STATE_DATA:
125 net_pkt_read_u8(ppp->tx_pkt, &byte);
126 ppp->tx_pkt_fcs = modem_ppp_fcs_update(ppp->tx_pkt_fcs, byte);
127
128 if ((byte == MODEM_PPP_CODE_DELIMITER) || (byte == MODEM_PPP_CODE_ESCAPE) ||
129 (byte < MODEM_PPP_VALUE_ESCAPE)) {
130 ppp->tx_pkt_escaped = byte ^ MODEM_PPP_VALUE_ESCAPE;
131 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_ESCAPING_DATA;
132 return MODEM_PPP_CODE_ESCAPE;
133 }
134
135 if (net_pkt_remaining_data(ppp->tx_pkt) == 0) {
136 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_FCS_LOW;
137 }
138
139 return byte;
140
141 case MODEM_PPP_TRANSMIT_STATE_ESCAPING_DATA:
142 if (net_pkt_remaining_data(ppp->tx_pkt) == 0) {
143 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_FCS_LOW;
144 } else {
145 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_DATA;
146 }
147
148 return ppp->tx_pkt_escaped;
149
150 /* Writing FCS */
151 case MODEM_PPP_TRANSMIT_STATE_FCS_LOW:
152 ppp->tx_pkt_fcs = modem_ppp_fcs_final(ppp->tx_pkt_fcs);
153 byte = ppp->tx_pkt_fcs & 0xFF;
154
155 if ((byte == MODEM_PPP_CODE_DELIMITER) || (byte == MODEM_PPP_CODE_ESCAPE) ||
156 (byte < MODEM_PPP_VALUE_ESCAPE)) {
157 ppp->tx_pkt_escaped = byte ^ MODEM_PPP_VALUE_ESCAPE;
158 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_ESCAPING_FCS_LOW;
159 return MODEM_PPP_CODE_ESCAPE;
160 }
161
162 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_FCS_HIGH;
163 return byte;
164
165 case MODEM_PPP_TRANSMIT_STATE_ESCAPING_FCS_LOW:
166 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_FCS_HIGH;
167 return ppp->tx_pkt_escaped;
168
169 case MODEM_PPP_TRANSMIT_STATE_FCS_HIGH:
170 byte = (ppp->tx_pkt_fcs >> 8) & 0xFF;
171
172 if ((byte == MODEM_PPP_CODE_DELIMITER) || (byte == MODEM_PPP_CODE_ESCAPE) ||
173 (byte < MODEM_PPP_VALUE_ESCAPE)) {
174 ppp->tx_pkt_escaped = byte ^ MODEM_PPP_VALUE_ESCAPE;
175 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_ESCAPING_FCS_HIGH;
176 return MODEM_PPP_CODE_ESCAPE;
177 }
178
179 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_EOF;
180 return byte;
181
182 case MODEM_PPP_TRANSMIT_STATE_ESCAPING_FCS_HIGH:
183 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_EOF;
184 return ppp->tx_pkt_escaped;
185
186 /* Writing end of frame */
187 case MODEM_PPP_TRANSMIT_STATE_EOF:
188 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_IDLE;
189 return MODEM_PPP_CODE_DELIMITER;
190 }
191
192 return 0;
193 }
194
modem_ppp_process_received_byte(struct modem_ppp * ppp,uint8_t byte)195 static void modem_ppp_process_received_byte(struct modem_ppp *ppp, uint8_t byte)
196 {
197 switch (ppp->receive_state) {
198 case MODEM_PPP_RECEIVE_STATE_HDR_SOF:
199 if (byte == MODEM_PPP_CODE_DELIMITER) {
200 ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_FF;
201 }
202
203 break;
204
205 case MODEM_PPP_RECEIVE_STATE_HDR_FF:
206 if (byte == MODEM_PPP_CODE_DELIMITER) {
207 break;
208 }
209
210 if (byte == 0xFF) {
211 ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_7D;
212 } else {
213 ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
214 }
215
216 break;
217
218 case MODEM_PPP_RECEIVE_STATE_HDR_7D:
219 if (byte == MODEM_PPP_CODE_ESCAPE) {
220 ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_23;
221 } else {
222 ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
223 }
224
225 break;
226
227 case MODEM_PPP_RECEIVE_STATE_HDR_23:
228 if (byte == 0x23) {
229 ppp->rx_pkt = net_pkt_rx_alloc_with_buffer(ppp->iface,
230 CONFIG_MODEM_PPP_NET_BUF_FRAG_SIZE, AF_UNSPEC, 0, K_NO_WAIT);
231
232 if (ppp->rx_pkt == NULL) {
233 LOG_WRN("Dropped frame, no net_pkt available");
234 ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
235 break;
236 }
237
238 LOG_DBG("Receiving PPP frame");
239 ppp->receive_state = MODEM_PPP_RECEIVE_STATE_WRITING;
240 net_pkt_cursor_init(ppp->rx_pkt);
241
242 } else {
243 ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
244 }
245
246 break;
247
248 case MODEM_PPP_RECEIVE_STATE_WRITING:
249 if (byte == MODEM_PPP_CODE_DELIMITER) {
250 LOG_DBG("Received PPP frame");
251
252 /* Remove FCS */
253 net_pkt_remove_tail(ppp->rx_pkt, MODEM_PPP_FRAME_TAIL_SIZE);
254 net_pkt_cursor_init(ppp->rx_pkt);
255 net_pkt_set_ppp(ppp->rx_pkt, true);
256
257 if (net_recv_data(ppp->iface, ppp->rx_pkt) < 0) {
258 LOG_WRN("Net pkt could not be processed");
259 net_pkt_unref(ppp->rx_pkt);
260 }
261
262 ppp->rx_pkt = NULL;
263 ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
264 break;
265 }
266
267 if (net_pkt_available_buffer(ppp->rx_pkt) == 1) {
268 if (net_pkt_alloc_buffer(ppp->rx_pkt, CONFIG_MODEM_PPP_NET_BUF_FRAG_SIZE,
269 AF_INET, K_NO_WAIT) < 0) {
270 LOG_WRN("Failed to alloc buffer");
271 net_pkt_unref(ppp->rx_pkt);
272 ppp->rx_pkt = NULL;
273 ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
274 break;
275 }
276 }
277
278 if (byte == MODEM_PPP_CODE_ESCAPE) {
279 ppp->receive_state = MODEM_PPP_RECEIVE_STATE_UNESCAPING;
280 break;
281 }
282
283 if (net_pkt_write_u8(ppp->rx_pkt, byte) < 0) {
284 LOG_WRN("Dropped PPP frame");
285 net_pkt_unref(ppp->rx_pkt);
286 ppp->rx_pkt = NULL;
287 ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
288 #if defined(CONFIG_NET_STATISTICS_PPP)
289 ppp->stats.drop++;
290 #endif
291 }
292
293 break;
294
295 case MODEM_PPP_RECEIVE_STATE_UNESCAPING:
296 if (net_pkt_write_u8(ppp->rx_pkt, (byte ^ MODEM_PPP_VALUE_ESCAPE)) < 0) {
297 LOG_WRN("Dropped PPP frame");
298 net_pkt_unref(ppp->rx_pkt);
299 ppp->rx_pkt = NULL;
300 ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
301 #if defined(CONFIG_NET_STATISTICS_PPP)
302 ppp->stats.drop++;
303 #endif
304 break;
305 }
306
307 ppp->receive_state = MODEM_PPP_RECEIVE_STATE_WRITING;
308 break;
309 }
310 }
311
modem_ppp_pipe_callback(struct modem_pipe * pipe,enum modem_pipe_event event,void * user_data)312 static void modem_ppp_pipe_callback(struct modem_pipe *pipe, enum modem_pipe_event event,
313 void *user_data)
314 {
315 struct modem_ppp *ppp = (struct modem_ppp *)user_data;
316
317 if (event == MODEM_PIPE_EVENT_RECEIVE_READY) {
318 k_work_submit(&ppp->process_work);
319 }
320 }
321
modem_ppp_send_handler(struct k_work * item)322 static void modem_ppp_send_handler(struct k_work *item)
323 {
324 struct modem_ppp *ppp = CONTAINER_OF(item, struct modem_ppp, send_work);
325 uint8_t byte;
326 uint8_t *reserved;
327 uint32_t reserved_size;
328 int ret;
329
330 if (ppp->tx_pkt == NULL) {
331 ppp->tx_pkt = k_fifo_get(&ppp->tx_pkt_fifo, K_NO_WAIT);
332 }
333
334 if (ppp->tx_pkt != NULL) {
335 /* Initialize wrap */
336 if (ppp->transmit_state == MODEM_PPP_TRANSMIT_STATE_IDLE) {
337 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_SOF;
338 }
339
340 /* Fill transmit ring buffer */
341 while (ring_buf_space_get(&ppp->transmit_rb) > 0) {
342 byte = modem_ppp_wrap_net_pkt_byte(ppp);
343
344 ring_buf_put(&ppp->transmit_rb, &byte, 1);
345
346 if (ppp->transmit_state == MODEM_PPP_TRANSMIT_STATE_IDLE) {
347 net_pkt_unref(ppp->tx_pkt);
348 ppp->tx_pkt = k_fifo_get(&ppp->tx_pkt_fifo, K_NO_WAIT);
349 break;
350 }
351 }
352 }
353
354 reserved_size = ring_buf_get_claim(&ppp->transmit_rb, &reserved, UINT32_MAX);
355 if (reserved_size == 0) {
356 ring_buf_get_finish(&ppp->transmit_rb, 0);
357 return;
358 }
359
360 ret = modem_pipe_transmit(ppp->pipe, reserved, reserved_size);
361 if (ret < 0) {
362 ring_buf_get_finish(&ppp->transmit_rb, 0);
363 } else {
364 ring_buf_get_finish(&ppp->transmit_rb, (uint32_t)ret);
365 }
366
367 /* Resubmit send work if data remains */
368 if ((ring_buf_is_empty(&ppp->transmit_rb) == false) || (ppp->tx_pkt != NULL)) {
369 k_work_submit(&ppp->send_work);
370 }
371 }
372
modem_ppp_process_handler(struct k_work * item)373 static void modem_ppp_process_handler(struct k_work *item)
374 {
375 struct modem_ppp *ppp = CONTAINER_OF(item, struct modem_ppp, process_work);
376 int ret;
377
378 ret = modem_pipe_receive(ppp->pipe, ppp->receive_buf, ppp->buf_size);
379 if (ret < 1) {
380 return;
381 }
382
383 for (int i = 0; i < ret; i++) {
384 modem_ppp_process_received_byte(ppp, ppp->receive_buf[i]);
385 }
386
387 k_work_submit(&ppp->process_work);
388 }
389
modem_ppp_ppp_api_init(struct net_if * iface)390 static void modem_ppp_ppp_api_init(struct net_if *iface)
391 {
392 const struct device *dev = net_if_get_device(iface);
393 struct modem_ppp *ppp = (struct modem_ppp *)dev->data;
394
395 net_ppp_init(iface);
396 net_if_flag_set(iface, NET_IF_NO_AUTO_START);
397 net_if_carrier_off(iface);
398
399 if (ppp->init_iface != NULL) {
400 ppp->init_iface(iface);
401 }
402
403 ppp->iface = iface;
404 }
405
modem_ppp_ppp_api_start(const struct device * dev)406 static int modem_ppp_ppp_api_start(const struct device *dev)
407 {
408 return 0;
409 }
410
modem_ppp_ppp_api_stop(const struct device * dev)411 static int modem_ppp_ppp_api_stop(const struct device *dev)
412 {
413 return 0;
414 }
415
modem_ppp_ppp_api_send(const struct device * dev,struct net_pkt * pkt)416 static int modem_ppp_ppp_api_send(const struct device *dev, struct net_pkt *pkt)
417 {
418 struct modem_ppp *ppp = (struct modem_ppp *)dev->data;
419
420 if (atomic_test_bit(&ppp->state, MODEM_PPP_STATE_ATTACHED_BIT) == false) {
421 return -EPERM;
422 }
423
424 /* Validate packet protocol */
425 if ((net_pkt_is_ppp(pkt) == false) && (net_pkt_family(pkt) != AF_INET) &&
426 (net_pkt_family(pkt) != AF_INET6)) {
427 return -EPROTONOSUPPORT;
428 }
429
430 /* Validate packet data length */
431 if (((net_pkt_get_len(pkt) < 2) && (net_pkt_is_ppp(pkt) == true)) ||
432 ((net_pkt_get_len(pkt) < 1))) {
433 return -ENODATA;
434 }
435
436 net_pkt_ref(pkt);
437 k_fifo_put(&ppp->tx_pkt_fifo, pkt);
438 k_work_submit(&ppp->send_work);
439 return 0;
440 }
441
442 #if defined(CONFIG_NET_STATISTICS_PPP)
modem_ppp_ppp_get_stats(const struct device * dev)443 static struct net_stats_ppp *modem_ppp_ppp_get_stats(const struct device *dev)
444 {
445 struct modem_ppp *ppp = (struct modem_ppp *)dev->data;
446
447 return &ppp->stats;
448 }
449 #endif
450
451 const struct ppp_api modem_ppp_ppp_api = {
452 .iface_api.init = modem_ppp_ppp_api_init,
453 .start = modem_ppp_ppp_api_start,
454 .stop = modem_ppp_ppp_api_stop,
455 .send = modem_ppp_ppp_api_send,
456 #if defined(CONFIG_NET_STATISTICS_PPP)
457 .get_stats = modem_ppp_ppp_get_stats,
458 #endif
459 };
460
modem_ppp_attach(struct modem_ppp * ppp,struct modem_pipe * pipe)461 int modem_ppp_attach(struct modem_ppp *ppp, struct modem_pipe *pipe)
462 {
463 if (atomic_test_and_set_bit(&ppp->state, MODEM_PPP_STATE_ATTACHED_BIT) == true) {
464 return 0;
465 }
466
467 modem_pipe_attach(pipe, modem_ppp_pipe_callback, ppp);
468 ppp->pipe = pipe;
469 return 0;
470 }
471
modem_ppp_get_iface(struct modem_ppp * ppp)472 struct net_if *modem_ppp_get_iface(struct modem_ppp *ppp)
473 {
474 return ppp->iface;
475 }
476
modem_ppp_release(struct modem_ppp * ppp)477 void modem_ppp_release(struct modem_ppp *ppp)
478 {
479 struct k_work_sync sync;
480 struct net_pkt *pkt;
481
482 if (atomic_test_and_clear_bit(&ppp->state, MODEM_PPP_STATE_ATTACHED_BIT) == false) {
483 return;
484 }
485
486 modem_pipe_release(ppp->pipe);
487 k_work_cancel_sync(&ppp->send_work, &sync);
488 k_work_cancel_sync(&ppp->process_work, &sync);
489 ppp->pipe = NULL;
490 ppp->receive_state = MODEM_PPP_RECEIVE_STATE_HDR_SOF;
491
492 if (ppp->rx_pkt != NULL) {
493 net_pkt_unref(ppp->rx_pkt);
494 ppp->rx_pkt = NULL;
495 }
496
497 ppp->transmit_state = MODEM_PPP_TRANSMIT_STATE_IDLE;
498
499 if (ppp->tx_pkt != NULL) {
500 net_pkt_unref(ppp->tx_pkt);
501 ppp->tx_pkt = NULL;
502 }
503
504 while (1) {
505 pkt = k_fifo_get(&ppp->tx_pkt_fifo, K_NO_WAIT);
506 if (pkt == NULL) {
507 break;
508 }
509
510 net_pkt_unref(pkt);
511 }
512 }
513
modem_ppp_init_internal(const struct device * dev)514 int modem_ppp_init_internal(const struct device *dev)
515 {
516 struct modem_ppp *ppp = (struct modem_ppp *)dev->data;
517
518 atomic_set(&ppp->state, 0);
519 ring_buf_init(&ppp->transmit_rb, ppp->buf_size, ppp->transmit_buf);
520 k_work_init(&ppp->send_work, modem_ppp_send_handler);
521 k_work_init(&ppp->process_work, modem_ppp_process_handler);
522 k_fifo_init(&ppp->tx_pkt_fifo);
523
524 return 0;
525 }
526