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