1 /*
2 * Copyright (c) 2022 Trackunit Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(modem_cmux, CONFIG_MODEM_MODULES_LOG_LEVEL);
9
10 #include <zephyr/kernel.h>
11 #include <zephyr/sys/crc.h>
12 #include <zephyr/modem/cmux.h>
13
14 #include <string.h>
15
16 #define MODEM_CMUX_FCS_POLYNOMIAL (0xE0)
17 #define MODEM_CMUX_FCS_INIT_VALUE (0xFF)
18 #define MODEM_CMUX_EA (0x01)
19 #define MODEM_CMUX_CR (0x02)
20 #define MODEM_CMUX_PF (0x10)
21 #define MODEM_CMUX_FRAME_SIZE_MAX (0x08)
22 #define MODEM_CMUX_DATA_SIZE_MIN (0x08)
23 #define MODEM_CMUX_DATA_FRAME_SIZE_MIN (MODEM_CMUX_FRAME_SIZE_MAX + \
24 MODEM_CMUX_DATA_SIZE_MIN)
25
26 #define MODEM_CMUX_CMD_DATA_SIZE_MAX (0x08)
27 #define MODEM_CMUX_CMD_FRAME_SIZE_MAX (MODEM_CMUX_FRAME_SIZE_MAX + \
28 MODEM_CMUX_CMD_DATA_SIZE_MAX)
29
30 #define MODEM_CMUX_T1_TIMEOUT (K_MSEC(330))
31 #define MODEM_CMUX_T2_TIMEOUT (K_MSEC(660))
32
33 #define MODEM_CMUX_EVENT_CONNECTED_BIT (BIT(0))
34 #define MODEM_CMUX_EVENT_DISCONNECTED_BIT (BIT(1))
35
36 enum modem_cmux_frame_types {
37 MODEM_CMUX_FRAME_TYPE_RR = 0x01,
38 MODEM_CMUX_FRAME_TYPE_UI = 0x03,
39 MODEM_CMUX_FRAME_TYPE_RNR = 0x05,
40 MODEM_CMUX_FRAME_TYPE_REJ = 0x09,
41 MODEM_CMUX_FRAME_TYPE_DM = 0x0F,
42 MODEM_CMUX_FRAME_TYPE_SABM = 0x2F,
43 MODEM_CMUX_FRAME_TYPE_DISC = 0x43,
44 MODEM_CMUX_FRAME_TYPE_UA = 0x63,
45 MODEM_CMUX_FRAME_TYPE_UIH = 0xEF,
46 };
47
48 enum modem_cmux_command_types {
49 MODEM_CMUX_COMMAND_NSC = 0x04,
50 MODEM_CMUX_COMMAND_TEST = 0x08,
51 MODEM_CMUX_COMMAND_PSC = 0x10,
52 MODEM_CMUX_COMMAND_RLS = 0x14,
53 MODEM_CMUX_COMMAND_FCOFF = 0x18,
54 MODEM_CMUX_COMMAND_PN = 0x20,
55 MODEM_CMUX_COMMAND_RPN = 0x24,
56 MODEM_CMUX_COMMAND_FCON = 0x28,
57 MODEM_CMUX_COMMAND_CLD = 0x30,
58 MODEM_CMUX_COMMAND_SNC = 0x34,
59 MODEM_CMUX_COMMAND_MSC = 0x38,
60 };
61
62 struct modem_cmux_command_type {
63 uint8_t ea: 1;
64 uint8_t cr: 1;
65 uint8_t value: 6;
66 };
67
68 struct modem_cmux_command_length {
69 uint8_t ea: 1;
70 uint8_t value: 7;
71 };
72
73 struct modem_cmux_command {
74 struct modem_cmux_command_type type;
75 struct modem_cmux_command_length length;
76 uint8_t value[];
77 };
78
modem_cmux_wrap_command(struct modem_cmux_command ** command,const uint8_t * data,uint16_t data_len)79 static int modem_cmux_wrap_command(struct modem_cmux_command **command, const uint8_t *data,
80 uint16_t data_len)
81 {
82 if ((data == NULL) || (data_len < 2)) {
83 return -EINVAL;
84 }
85
86 (*command) = (struct modem_cmux_command *)data;
87
88 if (((*command)->length.ea == 0) || ((*command)->type.ea == 0)) {
89 return -EINVAL;
90 }
91
92 if ((*command)->length.value != (data_len - 2)) {
93 return -EINVAL;
94 }
95
96 return 0;
97 }
98
modem_cmux_command_wrap(uint8_t * data)99 static struct modem_cmux_command *modem_cmux_command_wrap(uint8_t *data)
100 {
101 return (struct modem_cmux_command *)data;
102 }
103
modem_cmux_log_unknown_frame(struct modem_cmux * cmux)104 static void modem_cmux_log_unknown_frame(struct modem_cmux *cmux)
105 {
106 char data[24];
107 uint8_t data_cnt = (cmux->frame.data_len < 8) ? cmux->frame.data_len : 8;
108
109 for (uint8_t i = 0; i < data_cnt; i++) {
110 snprintk(&data[i * 3], sizeof(data) - (i * 3), "%02X,", cmux->frame.data[i]);
111 }
112
113 /* Remove trailing */
114 if (data_cnt > 0) {
115 data[(data_cnt * 3) - 1] = '\0';
116 }
117
118 LOG_DBG("ch:%u, type:%u, data:%s", cmux->frame.dlci_address, cmux->frame.type, data);
119 }
120
modem_cmux_raise_event(struct modem_cmux * cmux,enum modem_cmux_event event)121 static void modem_cmux_raise_event(struct modem_cmux *cmux, enum modem_cmux_event event)
122 {
123 if (cmux->callback == NULL) {
124 return;
125 }
126
127 cmux->callback(cmux, event, cmux->user_data);
128 }
129
modem_cmux_bus_callback(struct modem_pipe * pipe,enum modem_pipe_event event,void * user_data)130 static void modem_cmux_bus_callback(struct modem_pipe *pipe, enum modem_pipe_event event,
131 void *user_data)
132 {
133 struct modem_cmux *cmux = (struct modem_cmux *)user_data;
134
135 if (event == MODEM_PIPE_EVENT_RECEIVE_READY) {
136 k_work_schedule(&cmux->receive_work, K_NO_WAIT);
137 }
138 }
139
modem_cmux_transmit_frame(struct modem_cmux * cmux,const struct modem_cmux_frame * frame)140 static uint16_t modem_cmux_transmit_frame(struct modem_cmux *cmux,
141 const struct modem_cmux_frame *frame)
142 {
143 uint8_t byte;
144 uint8_t fcs;
145 uint16_t space;
146 uint16_t data_len;
147
148 space = ring_buf_space_get(&cmux->transmit_rb) - MODEM_CMUX_FRAME_SIZE_MAX;
149 data_len = (space < frame->data_len) ? space : frame->data_len;
150
151 /* SOF */
152 byte = 0xF9;
153 ring_buf_put(&cmux->transmit_rb, &byte, 1);
154
155 /* DLCI Address (Max 63) */
156 byte = 0x01 | (frame->cr << 1) | (frame->dlci_address << 2);
157 fcs = crc8(&byte, 1, MODEM_CMUX_FCS_POLYNOMIAL, MODEM_CMUX_FCS_INIT_VALUE, true);
158 ring_buf_put(&cmux->transmit_rb, &byte, 1);
159
160 /* Frame type and poll/final */
161 byte = frame->type | (frame->pf << 4);
162 fcs = crc8(&byte, 1, MODEM_CMUX_FCS_POLYNOMIAL, fcs, true);
163 ring_buf_put(&cmux->transmit_rb, &byte, 1);
164
165 /* Data length */
166 if (data_len > 127) {
167 byte = data_len << 1;
168 fcs = crc8(&byte, 1, MODEM_CMUX_FCS_POLYNOMIAL, fcs, true);
169 ring_buf_put(&cmux->transmit_rb, &byte, 1);
170 byte = 0x01 | (data_len >> 7);
171 ring_buf_put(&cmux->transmit_rb, &byte, 1);
172 } else {
173 byte = 0x01 | (data_len << 1);
174 ring_buf_put(&cmux->transmit_rb, &byte, 1);
175 }
176
177 /* FCS final */
178 if (frame->type == MODEM_CMUX_FRAME_TYPE_UIH) {
179 fcs = 0xFF - crc8(&byte, 1, MODEM_CMUX_FCS_POLYNOMIAL, fcs, true);
180 } else {
181 fcs = crc8(&byte, 1, MODEM_CMUX_FCS_POLYNOMIAL, fcs, true);
182 fcs = 0xFF - crc8(frame->data, data_len, MODEM_CMUX_FCS_POLYNOMIAL, fcs, true);
183 }
184
185 /* Data */
186 ring_buf_put(&cmux->transmit_rb, frame->data, data_len);
187
188 /* FCS */
189 ring_buf_put(&cmux->transmit_rb, &fcs, 1);
190
191 /* EOF */
192 byte = 0xF9;
193 ring_buf_put(&cmux->transmit_rb, &byte, 1);
194 k_work_schedule(&cmux->transmit_work, K_NO_WAIT);
195 return data_len;
196 }
197
modem_cmux_transmit_cmd_frame(struct modem_cmux * cmux,const struct modem_cmux_frame * frame)198 static bool modem_cmux_transmit_cmd_frame(struct modem_cmux *cmux,
199 const struct modem_cmux_frame *frame)
200 {
201 uint16_t space;
202
203 k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
204 space = ring_buf_space_get(&cmux->transmit_rb);
205
206 if (space < MODEM_CMUX_CMD_FRAME_SIZE_MAX) {
207 k_mutex_unlock(&cmux->transmit_rb_lock);
208 return false;
209 }
210
211 modem_cmux_transmit_frame(cmux, frame);
212 k_mutex_unlock(&cmux->transmit_rb_lock);
213 return true;
214 }
215
modem_cmux_transmit_data_frame(struct modem_cmux * cmux,const struct modem_cmux_frame * frame)216 static int16_t modem_cmux_transmit_data_frame(struct modem_cmux *cmux,
217 const struct modem_cmux_frame *frame)
218 {
219 uint16_t space;
220 int ret;
221
222 k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
223
224 if (cmux->flow_control_on == false) {
225 k_mutex_unlock(&cmux->transmit_rb_lock);
226 return 0;
227 }
228
229 space = ring_buf_space_get(&cmux->transmit_rb);
230
231 /*
232 * Two command frames are reserved for command channel, and we shall prefer
233 * waiting for more than MODEM_CMUX_DATA_FRAME_SIZE_MIN bytes available in the
234 * transmit buffer rather than transmitting a few bytes at a time. This avoids
235 * excessive wrapping overhead, since transmitting a single byte will require 8
236 * bytes of wrapping.
237 */
238 if (space < ((MODEM_CMUX_CMD_FRAME_SIZE_MAX * 2) + MODEM_CMUX_DATA_FRAME_SIZE_MIN)) {
239 k_mutex_unlock(&cmux->transmit_rb_lock);
240 return -ENOMEM;
241 }
242
243 ret = modem_cmux_transmit_frame(cmux, frame);
244 k_mutex_unlock(&cmux->transmit_rb_lock);
245 return ret;
246 }
247
modem_cmux_acknowledge_received_frame(struct modem_cmux * cmux)248 static void modem_cmux_acknowledge_received_frame(struct modem_cmux *cmux)
249 {
250 struct modem_cmux_command *command;
251 struct modem_cmux_frame frame;
252 uint8_t data[MODEM_CMUX_CMD_DATA_SIZE_MAX];
253
254 if (sizeof(data) < cmux->frame.data_len) {
255 LOG_WRN("Command acknowledge buffer overrun");
256 return;
257 }
258
259 memcpy(&frame, &cmux->frame, sizeof(cmux->frame));
260 memcpy(data, cmux->frame.data, cmux->frame.data_len);
261 modem_cmux_wrap_command(&command, data, cmux->frame.data_len);
262 command->type.cr = 0;
263 frame.data = data;
264 frame.data_len = cmux->frame.data_len;
265
266 if (modem_cmux_transmit_cmd_frame(cmux, &frame) == false) {
267 LOG_WRN("Command acknowledge buffer overrun");
268 }
269 }
270
modem_cmux_on_msc_command(struct modem_cmux * cmux)271 static void modem_cmux_on_msc_command(struct modem_cmux *cmux)
272 {
273 modem_cmux_acknowledge_received_frame(cmux);
274 }
275
modem_cmux_on_fcon_command(struct modem_cmux * cmux)276 static void modem_cmux_on_fcon_command(struct modem_cmux *cmux)
277 {
278 k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
279 cmux->flow_control_on = true;
280 k_mutex_unlock(&cmux->transmit_rb_lock);
281 modem_cmux_acknowledge_received_frame(cmux);
282 }
283
modem_cmux_on_fcoff_command(struct modem_cmux * cmux)284 static void modem_cmux_on_fcoff_command(struct modem_cmux *cmux)
285 {
286 k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
287 cmux->flow_control_on = false;
288 k_mutex_unlock(&cmux->transmit_rb_lock);
289 modem_cmux_acknowledge_received_frame(cmux);
290 }
291
modem_cmux_on_cld_command(struct modem_cmux * cmux)292 static void modem_cmux_on_cld_command(struct modem_cmux *cmux)
293 {
294 if (cmux->state != MODEM_CMUX_STATE_DISCONNECTING) {
295 LOG_WRN("Unexpected close down");
296 }
297
298 cmux->state = MODEM_CMUX_STATE_DISCONNECTED;
299 k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
300 cmux->flow_control_on = false;
301 k_mutex_unlock(&cmux->transmit_rb_lock);
302 k_work_cancel_delayable(&cmux->disconnect_work);
303 modem_cmux_raise_event(cmux, MODEM_CMUX_EVENT_DISCONNECTED);
304 k_event_clear(&cmux->event, MODEM_CMUX_EVENT_CONNECTED_BIT);
305 k_event_post(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT);
306 }
307
modem_cmux_on_control_frame_ua(struct modem_cmux * cmux)308 static void modem_cmux_on_control_frame_ua(struct modem_cmux *cmux)
309 {
310 if (cmux->state != MODEM_CMUX_STATE_CONNECTING) {
311 LOG_DBG("Unexpected UA frame");
312
313 return;
314 }
315
316 cmux->state = MODEM_CMUX_STATE_CONNECTED;
317 k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
318 cmux->flow_control_on = true;
319 k_mutex_unlock(&cmux->transmit_rb_lock);
320 k_work_cancel_delayable(&cmux->connect_work);
321 modem_cmux_raise_event(cmux, MODEM_CMUX_EVENT_CONNECTED);
322 k_event_clear(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT);
323 k_event_post(&cmux->event, MODEM_CMUX_EVENT_CONNECTED_BIT);
324 }
325
modem_cmux_on_control_frame_uih(struct modem_cmux * cmux)326 static void modem_cmux_on_control_frame_uih(struct modem_cmux *cmux)
327 {
328 struct modem_cmux_command *command;
329
330 if ((cmux->state != MODEM_CMUX_STATE_CONNECTED) &&
331 (cmux->state != MODEM_CMUX_STATE_DISCONNECTING)) {
332 LOG_DBG("Unexpected UIH frame");
333 return;
334 }
335
336 if (modem_cmux_wrap_command(&command, cmux->frame.data, cmux->frame.data_len) < 0) {
337 LOG_WRN("Invalid command");
338 return;
339 }
340
341 switch (command->type.value) {
342 case MODEM_CMUX_COMMAND_CLD:
343 modem_cmux_on_cld_command(cmux);
344 break;
345
346 case MODEM_CMUX_COMMAND_MSC:
347 modem_cmux_on_msc_command(cmux);
348 break;
349
350 case MODEM_CMUX_COMMAND_FCON:
351 modem_cmux_on_fcon_command(cmux);
352 break;
353
354 case MODEM_CMUX_COMMAND_FCOFF:
355 modem_cmux_on_fcoff_command(cmux);
356 break;
357
358 default:
359 LOG_DBG("Unknown command");
360 break;
361 }
362 }
363
modem_cmux_on_control_frame(struct modem_cmux * cmux)364 static void modem_cmux_on_control_frame(struct modem_cmux *cmux)
365 {
366 switch (cmux->frame.type) {
367 case MODEM_CMUX_FRAME_TYPE_UA:
368 modem_cmux_on_control_frame_ua(cmux);
369 break;
370
371 case MODEM_CMUX_FRAME_TYPE_UIH:
372 modem_cmux_on_control_frame_uih(cmux);
373 break;
374
375 default:
376 modem_cmux_log_unknown_frame(cmux);
377 break;
378 }
379 }
380
modem_cmux_find_dlci(struct modem_cmux * cmux)381 static struct modem_cmux_dlci *modem_cmux_find_dlci(struct modem_cmux *cmux)
382 {
383 sys_snode_t *node;
384 struct modem_cmux_dlci *dlci;
385
386 SYS_SLIST_FOR_EACH_NODE(&cmux->dlcis, node) {
387 dlci = (struct modem_cmux_dlci *)node;
388
389 if (dlci->dlci_address == cmux->frame.dlci_address) {
390 return dlci;
391 }
392 }
393
394 return NULL;
395 }
396
modem_cmux_on_dlci_frame_ua(struct modem_cmux_dlci * dlci)397 static void modem_cmux_on_dlci_frame_ua(struct modem_cmux_dlci *dlci)
398 {
399 switch (dlci->state) {
400 case MODEM_CMUX_DLCI_STATE_OPENING:
401 dlci->state = MODEM_CMUX_DLCI_STATE_OPEN;
402 modem_pipe_notify_opened(&dlci->pipe);
403 k_work_cancel_delayable(&dlci->open_work);
404 break;
405
406 case MODEM_CMUX_DLCI_STATE_CLOSING:
407 dlci->state = MODEM_CMUX_DLCI_STATE_CLOSED;
408 modem_pipe_notify_closed(&dlci->pipe);
409 k_work_cancel_delayable(&dlci->close_work);
410 break;
411
412 default:
413 LOG_DBG("Unexpected UA frame");
414 break;
415 }
416 }
417
modem_cmux_on_dlci_frame_uih(struct modem_cmux_dlci * dlci)418 static void modem_cmux_on_dlci_frame_uih(struct modem_cmux_dlci *dlci)
419 {
420 struct modem_cmux *cmux = dlci->cmux;
421
422 if (dlci->state != MODEM_CMUX_DLCI_STATE_OPEN) {
423 LOG_DBG("Unexpected UIH frame");
424 return;
425 }
426
427 k_mutex_lock(&dlci->receive_rb_lock, K_FOREVER);
428 ring_buf_put(&dlci->receive_rb, cmux->frame.data, cmux->frame.data_len);
429 k_mutex_unlock(&dlci->receive_rb_lock);
430 modem_pipe_notify_receive_ready(&dlci->pipe);
431 }
432
modem_cmux_on_dlci_frame(struct modem_cmux * cmux)433 static void modem_cmux_on_dlci_frame(struct modem_cmux *cmux)
434 {
435 struct modem_cmux_dlci *dlci;
436
437 dlci = modem_cmux_find_dlci(cmux);
438
439 if (dlci == NULL) {
440 LOG_WRN("Could not find DLCI: %u", cmux->frame.dlci_address);
441
442 return;
443 }
444
445 switch (cmux->frame.type) {
446 case MODEM_CMUX_FRAME_TYPE_UA:
447 modem_cmux_on_dlci_frame_ua(dlci);
448 break;
449
450 case MODEM_CMUX_FRAME_TYPE_UIH:
451 modem_cmux_on_dlci_frame_uih(dlci);
452 break;
453
454 default:
455 modem_cmux_log_unknown_frame(cmux);
456 break;
457 }
458 }
459
modem_cmux_on_frame(struct modem_cmux * cmux)460 static void modem_cmux_on_frame(struct modem_cmux *cmux)
461 {
462 if (cmux->frame.dlci_address == 0) {
463 modem_cmux_on_control_frame(cmux);
464 return;
465 }
466
467 modem_cmux_on_dlci_frame(cmux);
468 }
469
modem_cmux_process_received_byte(struct modem_cmux * cmux,uint8_t byte)470 static void modem_cmux_process_received_byte(struct modem_cmux *cmux, uint8_t byte)
471 {
472 uint8_t fcs;
473 static const uint8_t resync[3] = {0xF9, 0xF9, 0xF9};
474
475 switch (cmux->receive_state) {
476 case MODEM_CMUX_RECEIVE_STATE_SOF:
477 if (byte == 0xF9) {
478 cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_ADDRESS;
479 break;
480 }
481
482 /* Send resync flags */
483 modem_pipe_transmit(cmux->pipe, resync, sizeof(resync));
484
485 /* Await resync flags */
486 cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_RESYNC_0;
487 break;
488
489 case MODEM_CMUX_RECEIVE_STATE_RESYNC_0:
490 if (byte == 0xF9) {
491 cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_RESYNC_1;
492 }
493
494 break;
495
496 case MODEM_CMUX_RECEIVE_STATE_RESYNC_1:
497 if (byte == 0xF9) {
498 cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_RESYNC_2;
499 } else {
500 cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_RESYNC_0;
501 }
502
503 break;
504
505 case MODEM_CMUX_RECEIVE_STATE_RESYNC_2:
506 if (byte == 0xF9) {
507 cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_RESYNC_3;
508 } else {
509 cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_RESYNC_0;
510 }
511
512 break;
513
514 case MODEM_CMUX_RECEIVE_STATE_RESYNC_3:
515 if (byte == 0xF9) {
516 break;
517 }
518
519 case MODEM_CMUX_RECEIVE_STATE_ADDRESS:
520 /* Initialize */
521 cmux->receive_buf_len = 0;
522 cmux->frame_header_len = 0;
523
524 /* Store header for FCS */
525 cmux->frame_header[cmux->frame_header_len] = byte;
526 cmux->frame_header_len++;
527
528 /* Get CR */
529 cmux->frame.cr = (byte & 0x02) ? true : false;
530
531 /* Get DLCI address */
532 cmux->frame.dlci_address = (byte >> 2) & 0x3F;
533
534 /* Await control */
535 cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_CONTROL;
536 break;
537
538 case MODEM_CMUX_RECEIVE_STATE_CONTROL:
539 /* Store header for FCS */
540 cmux->frame_header[cmux->frame_header_len] = byte;
541 cmux->frame_header_len++;
542
543 /* Get PF */
544 cmux->frame.pf = (byte & MODEM_CMUX_PF) ? true : false;
545
546 /* Get frame type */
547 cmux->frame.type = byte & (~MODEM_CMUX_PF);
548
549 /* Await data length */
550 cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_LENGTH;
551 break;
552
553 case MODEM_CMUX_RECEIVE_STATE_LENGTH:
554 /* Store header for FCS */
555 cmux->frame_header[cmux->frame_header_len] = byte;
556 cmux->frame_header_len++;
557
558 /* Get first 7 bits of data length */
559 cmux->frame.data_len = (byte >> 1);
560
561 /* Check if length field continues */
562 if ((byte & MODEM_CMUX_EA) == 0) {
563 /* Await continued length field */
564 cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_LENGTH_CONT;
565 break;
566 }
567
568 /* Check if no data field */
569 if (cmux->frame.data_len == 0) {
570 /* Await FCS */
571 cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_FCS;
572 break;
573 }
574
575 /* Await data */
576 cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_DATA;
577 break;
578
579 case MODEM_CMUX_RECEIVE_STATE_LENGTH_CONT:
580 /* Store header for FCS */
581 cmux->frame_header[cmux->frame_header_len] = byte;
582 cmux->frame_header_len++;
583
584 /* Get last 8 bits of data length */
585 cmux->frame.data_len |= ((uint16_t)byte) << 7;
586
587 /* Await data */
588 cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_DATA;
589 break;
590
591 case MODEM_CMUX_RECEIVE_STATE_DATA:
592 /* Copy byte to data */
593 cmux->receive_buf[cmux->receive_buf_len] = byte;
594 cmux->receive_buf_len++;
595
596 /* Check if datalen reached */
597 if (cmux->frame.data_len == cmux->receive_buf_len) {
598 /* Await FCS */
599 cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_FCS;
600 break;
601 }
602
603 /* Check if receive buffer overrun */
604 if (cmux->receive_buf_len == cmux->receive_buf_size) {
605 LOG_DBG("Receive buf overrun");
606
607 /* Drop frame */
608 cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_EOF;
609 break;
610 }
611
612 break;
613
614 case MODEM_CMUX_RECEIVE_STATE_FCS:
615 /* Compute FCS */
616 if (cmux->frame.type == MODEM_CMUX_FRAME_TYPE_UIH) {
617 fcs = 0xFF - crc8(cmux->frame_header, cmux->frame_header_len,
618 MODEM_CMUX_FCS_POLYNOMIAL, MODEM_CMUX_FCS_INIT_VALUE,
619 true);
620 } else {
621 fcs = crc8(cmux->frame_header, cmux->frame_header_len,
622 MODEM_CMUX_FCS_POLYNOMIAL, MODEM_CMUX_FCS_INIT_VALUE, true);
623
624 fcs = 0xFF - crc8(cmux->frame.data, cmux->frame.data_len,
625 MODEM_CMUX_FCS_POLYNOMIAL, fcs, true);
626 }
627
628 /* Validate FCS */
629 if (fcs != byte) {
630 LOG_WRN("Frame FCS error");
631
632 /* Drop frame */
633 cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_DROP;
634 break;
635 }
636
637 cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_EOF;
638 break;
639
640 case MODEM_CMUX_RECEIVE_STATE_DROP:
641 LOG_WRN("Dropped frame");
642 cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_SOF;
643 break;
644
645 case MODEM_CMUX_RECEIVE_STATE_EOF:
646 /* Validate byte is EOF */
647 if (byte != 0xF9) {
648 /* Unexpected byte */
649 cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_SOF;
650 break;
651 }
652
653 LOG_DBG("Received frame");
654
655 /* Process frame */
656 cmux->frame.data = cmux->receive_buf;
657 modem_cmux_on_frame(cmux);
658
659 /* Await start of next frame */
660 cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_SOF;
661 break;
662
663 default:
664 break;
665 }
666 }
667
modem_cmux_receive_handler(struct k_work * item)668 static void modem_cmux_receive_handler(struct k_work *item)
669 {
670 struct k_work_delayable *dwork = k_work_delayable_from_work(item);
671 struct modem_cmux *cmux = CONTAINER_OF(dwork, struct modem_cmux, receive_work);
672 uint8_t buf[16];
673 int ret;
674
675 /* Receive data from pipe */
676 ret = modem_pipe_receive(cmux->pipe, buf, sizeof(buf));
677 if (ret < 1) {
678 return;
679 }
680
681 /* Process received data */
682 for (uint16_t i = 0; i < (uint16_t)ret; i++) {
683 modem_cmux_process_received_byte(cmux, buf[i]);
684 }
685
686 /* Reschedule received work */
687 k_work_schedule(&cmux->receive_work, K_NO_WAIT);
688 }
689
modem_cmux_transmit_handler(struct k_work * item)690 static void modem_cmux_transmit_handler(struct k_work *item)
691 {
692 struct k_work_delayable *dwork = k_work_delayable_from_work(item);
693 struct modem_cmux *cmux = CONTAINER_OF(dwork, struct modem_cmux, transmit_work);
694 uint8_t *reserved;
695 uint32_t reserved_size;
696 int ret;
697
698 k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
699
700 /* Reserve data to transmit from transmit ring buffer */
701 reserved_size = ring_buf_get_claim(&cmux->transmit_rb, &reserved, UINT32_MAX);
702
703 /* Transmit reserved data */
704 ret = modem_pipe_transmit(cmux->pipe, reserved, reserved_size);
705 if (ret < 1) {
706 ring_buf_get_finish(&cmux->transmit_rb, 0);
707 k_mutex_unlock(&cmux->transmit_rb_lock);
708 k_work_schedule(&cmux->transmit_work, K_NO_WAIT);
709
710 return;
711 }
712
713 /* Release remaining reserved data */
714 ring_buf_get_finish(&cmux->transmit_rb, ret);
715
716 /* Resubmit transmit work if data remains */
717 if (ring_buf_is_empty(&cmux->transmit_rb) == false) {
718 k_work_schedule(&cmux->transmit_work, K_NO_WAIT);
719 }
720
721 k_mutex_unlock(&cmux->transmit_rb_lock);
722 }
723
modem_cmux_connect_handler(struct k_work * item)724 static void modem_cmux_connect_handler(struct k_work *item)
725 {
726 struct k_work_delayable *dwork = k_work_delayable_from_work(item);
727 struct modem_cmux *cmux = CONTAINER_OF(dwork, struct modem_cmux, connect_work);
728
729 cmux->state = MODEM_CMUX_STATE_CONNECTING;
730
731 struct modem_cmux_frame frame = {
732 .dlci_address = 0,
733 .cr = true,
734 .pf = true,
735 .type = MODEM_CMUX_FRAME_TYPE_SABM,
736 .data = NULL,
737 .data_len = 0,
738 };
739
740 modem_cmux_transmit_cmd_frame(cmux, &frame);
741 k_work_schedule(&cmux->connect_work, MODEM_CMUX_T1_TIMEOUT);
742 }
743
modem_cmux_disconnect_handler(struct k_work * item)744 static void modem_cmux_disconnect_handler(struct k_work *item)
745 {
746 struct k_work_delayable *dwork = k_work_delayable_from_work(item);
747 struct modem_cmux *cmux = CONTAINER_OF(dwork, struct modem_cmux, disconnect_work);
748 struct modem_cmux_command *command;
749 uint8_t data[2];
750
751 cmux->state = MODEM_CMUX_STATE_DISCONNECTING;
752
753 command = modem_cmux_command_wrap(data);
754 command->type.ea = 1;
755 command->type.cr = 1;
756 command->type.value = MODEM_CMUX_COMMAND_CLD;
757 command->length.ea = 1;
758 command->length.value = 0;
759
760 struct modem_cmux_frame frame = {
761 .dlci_address = 0,
762 .cr = true,
763 .pf = false,
764 .type = MODEM_CMUX_FRAME_TYPE_UIH,
765 .data = data,
766 .data_len = sizeof(data),
767 };
768
769 /* Transmit close down command */
770 modem_cmux_transmit_cmd_frame(cmux, &frame);
771 k_work_schedule(&cmux->disconnect_work, MODEM_CMUX_T1_TIMEOUT);
772 }
773
modem_cmux_dlci_pipe_api_open(void * data)774 static int modem_cmux_dlci_pipe_api_open(void *data)
775 {
776 struct modem_cmux_dlci *dlci = (struct modem_cmux_dlci *)data;
777
778 if (k_work_delayable_is_pending(&dlci->open_work) == true) {
779 return -EBUSY;
780 }
781
782 k_work_schedule(&dlci->open_work, K_NO_WAIT);
783 return 0;
784 }
785
modem_cmux_dlci_pipe_api_transmit(void * data,const uint8_t * buf,size_t size)786 static int modem_cmux_dlci_pipe_api_transmit(void *data, const uint8_t *buf, size_t size)
787 {
788 struct modem_cmux_dlci *dlci = (struct modem_cmux_dlci *)data;
789 struct modem_cmux *cmux = dlci->cmux;
790
791 struct modem_cmux_frame frame = {
792 .dlci_address = dlci->dlci_address,
793 .cr = true,
794 .pf = false,
795 .type = MODEM_CMUX_FRAME_TYPE_UIH,
796 .data = buf,
797 .data_len = size,
798 };
799
800 return modem_cmux_transmit_data_frame(cmux, &frame);
801 }
802
modem_cmux_dlci_pipe_api_receive(void * data,uint8_t * buf,size_t size)803 static int modem_cmux_dlci_pipe_api_receive(void *data, uint8_t *buf, size_t size)
804 {
805 struct modem_cmux_dlci *dlci = (struct modem_cmux_dlci *)data;
806 uint32_t ret;
807
808 k_mutex_lock(&dlci->receive_rb_lock, K_FOREVER);
809 ret = ring_buf_get(&dlci->receive_rb, buf, size);
810 k_mutex_unlock(&dlci->receive_rb_lock);
811 return ret;
812 }
813
modem_cmux_dlci_pipe_api_close(void * data)814 static int modem_cmux_dlci_pipe_api_close(void *data)
815 {
816 struct modem_cmux_dlci *dlci = (struct modem_cmux_dlci *)data;
817
818 if (k_work_delayable_is_pending(&dlci->close_work) == true) {
819 return -EBUSY;
820 }
821
822 k_work_schedule(&dlci->close_work, K_NO_WAIT);
823 return 0;
824 }
825
826 struct modem_pipe_api modem_cmux_dlci_pipe_api = {
827 .open = modem_cmux_dlci_pipe_api_open,
828 .transmit = modem_cmux_dlci_pipe_api_transmit,
829 .receive = modem_cmux_dlci_pipe_api_receive,
830 .close = modem_cmux_dlci_pipe_api_close,
831 };
832
modem_cmux_dlci_open_handler(struct k_work * item)833 static void modem_cmux_dlci_open_handler(struct k_work *item)
834 {
835 struct k_work_delayable *dwork = k_work_delayable_from_work(item);
836 struct modem_cmux_dlci *dlci = CONTAINER_OF(dwork, struct modem_cmux_dlci, open_work);
837
838 dlci->state = MODEM_CMUX_DLCI_STATE_OPENING;
839
840 struct modem_cmux_frame frame = {
841 .dlci_address = dlci->dlci_address,
842 .cr = true,
843 .pf = true,
844 .type = MODEM_CMUX_FRAME_TYPE_SABM,
845 .data = NULL,
846 .data_len = 0,
847 };
848
849 modem_cmux_transmit_cmd_frame(dlci->cmux, &frame);
850 k_work_schedule(&dlci->open_work, MODEM_CMUX_T1_TIMEOUT);
851 }
852
modem_cmux_dlci_close_handler(struct k_work * item)853 static void modem_cmux_dlci_close_handler(struct k_work *item)
854 {
855 struct k_work_delayable *dwork = k_work_delayable_from_work(item);
856 struct modem_cmux_dlci *dlci = CONTAINER_OF(dwork, struct modem_cmux_dlci, close_work);
857 struct modem_cmux *cmux = dlci->cmux;
858
859 dlci->state = MODEM_CMUX_DLCI_STATE_CLOSING;
860
861 struct modem_cmux_frame frame = {
862 .dlci_address = dlci->dlci_address,
863 .cr = true,
864 .pf = true,
865 .type = MODEM_CMUX_FRAME_TYPE_DISC,
866 .data = NULL,
867 .data_len = 0,
868 };
869
870 modem_cmux_transmit_cmd_frame(cmux, &frame);
871 k_work_schedule(&dlci->close_work, MODEM_CMUX_T1_TIMEOUT);
872 }
873
modem_cmux_dlci_pipes_notify_closed(struct modem_cmux * cmux)874 static void modem_cmux_dlci_pipes_notify_closed(struct modem_cmux *cmux)
875 {
876 sys_snode_t *node;
877 struct modem_cmux_dlci *dlci;
878
879 SYS_SLIST_FOR_EACH_NODE(&cmux->dlcis, node) {
880 dlci = (struct modem_cmux_dlci *)node;
881 modem_pipe_notify_closed(&dlci->pipe);
882 }
883 }
884
modem_cmux_init(struct modem_cmux * cmux,const struct modem_cmux_config * config)885 void modem_cmux_init(struct modem_cmux *cmux, const struct modem_cmux_config *config)
886 {
887 __ASSERT_NO_MSG(cmux != NULL);
888 __ASSERT_NO_MSG(config != NULL);
889 __ASSERT_NO_MSG(config->receive_buf != NULL);
890 __ASSERT_NO_MSG(config->receive_buf_size >= 126);
891 __ASSERT_NO_MSG(config->transmit_buf != NULL);
892 __ASSERT_NO_MSG(config->transmit_buf_size >= 148);
893
894 memset(cmux, 0x00, sizeof(*cmux));
895 cmux->callback = config->callback;
896 cmux->user_data = config->user_data;
897 cmux->receive_buf = config->receive_buf;
898 cmux->receive_buf_size = config->receive_buf_size;
899 sys_slist_init(&cmux->dlcis);
900 cmux->state = MODEM_CMUX_STATE_DISCONNECTED;
901 ring_buf_init(&cmux->transmit_rb, config->transmit_buf_size, config->transmit_buf);
902 k_mutex_init(&cmux->transmit_rb_lock);
903 k_work_init_delayable(&cmux->receive_work, modem_cmux_receive_handler);
904 k_work_init_delayable(&cmux->transmit_work, modem_cmux_transmit_handler);
905 k_work_init_delayable(&cmux->connect_work, modem_cmux_connect_handler);
906 k_work_init_delayable(&cmux->disconnect_work, modem_cmux_disconnect_handler);
907 k_event_init(&cmux->event);
908 k_event_post(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT);
909 }
910
modem_cmux_dlci_init(struct modem_cmux * cmux,struct modem_cmux_dlci * dlci,const struct modem_cmux_dlci_config * config)911 struct modem_pipe *modem_cmux_dlci_init(struct modem_cmux *cmux, struct modem_cmux_dlci *dlci,
912 const struct modem_cmux_dlci_config *config)
913 {
914 __ASSERT_NO_MSG(cmux != NULL);
915 __ASSERT_NO_MSG(dlci != NULL);
916 __ASSERT_NO_MSG(config != NULL);
917 __ASSERT_NO_MSG(config->dlci_address < 64);
918 __ASSERT_NO_MSG(config->receive_buf != NULL);
919 __ASSERT_NO_MSG(config->receive_buf_size >= 126);
920
921 memset(dlci, 0x00, sizeof(*dlci));
922 dlci->cmux = cmux;
923 dlci->dlci_address = config->dlci_address;
924 ring_buf_init(&dlci->receive_rb, config->receive_buf_size, config->receive_buf);
925 k_mutex_init(&dlci->receive_rb_lock);
926 modem_pipe_init(&dlci->pipe, dlci, &modem_cmux_dlci_pipe_api);
927 k_work_init_delayable(&dlci->open_work, modem_cmux_dlci_open_handler);
928 k_work_init_delayable(&dlci->close_work, modem_cmux_dlci_close_handler);
929 dlci->state = MODEM_CMUX_DLCI_STATE_CLOSED;
930 sys_slist_append(&dlci->cmux->dlcis, &dlci->node);
931 return &dlci->pipe;
932 }
933
modem_cmux_attach(struct modem_cmux * cmux,struct modem_pipe * pipe)934 int modem_cmux_attach(struct modem_cmux *cmux, struct modem_pipe *pipe)
935 {
936 cmux->pipe = pipe;
937 ring_buf_reset(&cmux->transmit_rb);
938 modem_pipe_attach(cmux->pipe, modem_cmux_bus_callback, cmux);
939 return 0;
940 }
941
modem_cmux_connect(struct modem_cmux * cmux)942 int modem_cmux_connect(struct modem_cmux *cmux)
943 {
944 __ASSERT_NO_MSG(cmux->pipe != NULL);
945
946 if (k_event_wait(&cmux->event, MODEM_CMUX_EVENT_CONNECTED_BIT, false, K_NO_WAIT)) {
947 return -EALREADY;
948 }
949
950 if (k_work_delayable_is_pending(&cmux->connect_work) == false) {
951 k_work_schedule(&cmux->connect_work, K_NO_WAIT);
952 }
953
954 if (k_event_wait(&cmux->event, MODEM_CMUX_EVENT_CONNECTED_BIT, false,
955 MODEM_CMUX_T2_TIMEOUT) == 0) {
956 return -EAGAIN;
957 }
958
959 return 0;
960 }
961
modem_cmux_connect_async(struct modem_cmux * cmux)962 int modem_cmux_connect_async(struct modem_cmux *cmux)
963 {
964 __ASSERT_NO_MSG(cmux->pipe != NULL);
965
966 if (k_work_delayable_is_pending(&cmux->connect_work) == true) {
967 return -EBUSY;
968 }
969
970 k_work_schedule(&cmux->connect_work, K_NO_WAIT);
971 return 0;
972 }
973
modem_cmux_disconnect(struct modem_cmux * cmux)974 int modem_cmux_disconnect(struct modem_cmux *cmux)
975 {
976 if (k_event_wait(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT, false, K_NO_WAIT)) {
977 return -EALREADY;
978 }
979
980 if (k_work_delayable_is_pending(&cmux->disconnect_work) == false) {
981 k_work_schedule(&cmux->disconnect_work, K_NO_WAIT);
982 }
983
984 if (k_event_wait(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT, false,
985 MODEM_CMUX_T2_TIMEOUT) == 0) {
986 return -EAGAIN;
987 }
988
989 return 0;
990 }
991
modem_cmux_disconnect_async(struct modem_cmux * cmux)992 int modem_cmux_disconnect_async(struct modem_cmux *cmux)
993 {
994 if (k_work_delayable_is_pending(&cmux->disconnect_work) == true) {
995 return -EBUSY;
996 }
997
998 k_work_schedule(&cmux->disconnect_work, K_NO_WAIT);
999 return 0;
1000 }
1001
modem_cmux_release(struct modem_cmux * cmux)1002 void modem_cmux_release(struct modem_cmux *cmux)
1003 {
1004 struct k_work_sync sync;
1005
1006 /* Close DLCI pipes */
1007 modem_cmux_dlci_pipes_notify_closed(cmux);
1008
1009 /* Release bus pipe */
1010 if (cmux->pipe) {
1011 modem_pipe_release(cmux->pipe);
1012 }
1013
1014 /* Cancel all work */
1015 k_work_cancel_delayable_sync(&cmux->connect_work, &sync);
1016 k_work_cancel_delayable_sync(&cmux->disconnect_work, &sync);
1017 k_work_cancel_delayable_sync(&cmux->transmit_work, &sync);
1018 k_work_cancel_delayable_sync(&cmux->receive_work, &sync);
1019
1020 /* Unreference pipe */
1021 cmux->pipe = NULL;
1022 }
1023