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_CMUX_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(const uint8_t * data)99 static struct modem_cmux_command *modem_cmux_command_wrap(const uint8_t *data)
100 {
101 	return (struct modem_cmux_command *)data;
102 }
103 
modem_cmux_frame_type_to_str(enum modem_cmux_frame_types frame_type)104 static const char *modem_cmux_frame_type_to_str(enum modem_cmux_frame_types frame_type)
105 {
106 	switch (frame_type) {
107 	case MODEM_CMUX_FRAME_TYPE_RR:
108 		return "RR";
109 	case MODEM_CMUX_FRAME_TYPE_UI:
110 		return "UI";
111 	case MODEM_CMUX_FRAME_TYPE_RNR:
112 		return "RNR";
113 	case MODEM_CMUX_FRAME_TYPE_REJ:
114 		return "REJ";
115 	case MODEM_CMUX_FRAME_TYPE_DM:
116 		return "DM";
117 	case MODEM_CMUX_FRAME_TYPE_SABM:
118 		return "SABM";
119 	case MODEM_CMUX_FRAME_TYPE_DISC:
120 		return "DISC";
121 	case MODEM_CMUX_FRAME_TYPE_UA:
122 		return "UA";
123 	case MODEM_CMUX_FRAME_TYPE_UIH:
124 		return "UIH";
125 	}
126 	return "";
127 }
128 
modem_cmux_log_frame(const struct modem_cmux_frame * frame,const char * action,size_t hexdump_len)129 static void modem_cmux_log_frame(const struct modem_cmux_frame *frame,
130 				 const char *action, size_t hexdump_len)
131 {
132 	LOG_DBG("%s ch:%u cr:%u pf:%u type:%s dlen:%u", action, frame->dlci_address,
133 		frame->cr, frame->pf, modem_cmux_frame_type_to_str(frame->type), frame->data_len);
134 	LOG_HEXDUMP_DBG(frame->data, hexdump_len, "data:");
135 }
136 
modem_cmux_log_transmit_frame(const struct modem_cmux_frame * frame)137 static void modem_cmux_log_transmit_frame(const struct modem_cmux_frame *frame)
138 {
139 	modem_cmux_log_frame(frame, "tx", frame->data_len);
140 }
141 
modem_cmux_log_received_frame(const struct modem_cmux_frame * frame)142 static void modem_cmux_log_received_frame(const struct modem_cmux_frame *frame)
143 {
144 	modem_cmux_log_frame(frame, "rcvd", frame->data_len);
145 }
146 
147 #if CONFIG_MODEM_STATS
modem_cmux_get_receive_buf_length(struct modem_cmux * cmux)148 static uint32_t modem_cmux_get_receive_buf_length(struct modem_cmux *cmux)
149 {
150 	return cmux->receive_buf_len;
151 }
152 
modem_cmux_get_receive_buf_size(struct modem_cmux * cmux)153 static uint32_t modem_cmux_get_receive_buf_size(struct modem_cmux *cmux)
154 {
155 	return cmux->receive_buf_size;
156 }
157 
modem_cmux_get_transmit_buf_length(struct modem_cmux * cmux)158 static uint32_t modem_cmux_get_transmit_buf_length(struct modem_cmux *cmux)
159 {
160 	return ring_buf_size_get(&cmux->transmit_rb);
161 }
162 
modem_cmux_get_transmit_buf_size(struct modem_cmux * cmux)163 static uint32_t modem_cmux_get_transmit_buf_size(struct modem_cmux *cmux)
164 {
165 	return ring_buf_capacity_get(&cmux->transmit_rb);
166 }
167 
modem_cmux_init_buf_stats(struct modem_cmux * cmux)168 static void modem_cmux_init_buf_stats(struct modem_cmux *cmux)
169 {
170 	uint32_t size;
171 
172 	size = modem_cmux_get_receive_buf_size(cmux);
173 	modem_stats_buffer_init(&cmux->receive_buf_stats, "cmux_rx", size);
174 	size = modem_cmux_get_transmit_buf_size(cmux);
175 	modem_stats_buffer_init(&cmux->transmit_buf_stats, "cmux_tx", size);
176 }
177 
modem_cmux_advertise_transmit_buf_stats(struct modem_cmux * cmux)178 static void modem_cmux_advertise_transmit_buf_stats(struct modem_cmux *cmux)
179 {
180 	uint32_t length;
181 
182 	length = modem_cmux_get_transmit_buf_length(cmux);
183 	modem_stats_buffer_advertise_length(&cmux->transmit_buf_stats, length);
184 }
185 
modem_cmux_advertise_receive_buf_stats(struct modem_cmux * cmux)186 static void modem_cmux_advertise_receive_buf_stats(struct modem_cmux *cmux)
187 {
188 	uint32_t length;
189 
190 	length = modem_cmux_get_receive_buf_length(cmux);
191 	modem_stats_buffer_advertise_length(&cmux->receive_buf_stats, length);
192 }
193 #endif
194 
modem_cmux_command_type_to_str(enum modem_cmux_command_types command_type)195 static const char *modem_cmux_command_type_to_str(enum modem_cmux_command_types command_type)
196 {
197 	switch (command_type) {
198 	case MODEM_CMUX_COMMAND_NSC:
199 		return "NSC";
200 	case MODEM_CMUX_COMMAND_TEST:
201 		return "TEST";
202 	case MODEM_CMUX_COMMAND_PSC:
203 		return "PSC";
204 	case MODEM_CMUX_COMMAND_RLS:
205 		return "RLS";
206 	case MODEM_CMUX_COMMAND_FCOFF:
207 		return "FCOFF";
208 	case MODEM_CMUX_COMMAND_PN:
209 		return "PN";
210 	case MODEM_CMUX_COMMAND_RPN:
211 		return "RPN";
212 	case MODEM_CMUX_COMMAND_FCON:
213 		return "FCON";
214 	case MODEM_CMUX_COMMAND_CLD:
215 		return "CLD";
216 	case MODEM_CMUX_COMMAND_SNC:
217 		return "SNC";
218 	case MODEM_CMUX_COMMAND_MSC:
219 		return "MSC";
220 	}
221 	return "";
222 }
223 
modem_cmux_log_transmit_command(const struct modem_cmux_command * command)224 static void modem_cmux_log_transmit_command(const struct modem_cmux_command *command)
225 {
226 	LOG_DBG("ea:%u,cr:%u,type:%s", command->type.ea, command->type.cr,
227 		modem_cmux_command_type_to_str(command->type.value));
228 	LOG_HEXDUMP_DBG(command->value, command->length.value, "data:");
229 }
230 
modem_cmux_log_received_command(const struct modem_cmux_command * command)231 static void modem_cmux_log_received_command(const struct modem_cmux_command *command)
232 {
233 	LOG_DBG("ea:%u,cr:%u,type:%s", command->type.ea, command->type.cr,
234 		modem_cmux_command_type_to_str(command->type.value));
235 	LOG_HEXDUMP_DBG(command->value, command->length.value, "data:");
236 }
237 
modem_cmux_raise_event(struct modem_cmux * cmux,enum modem_cmux_event event)238 static void modem_cmux_raise_event(struct modem_cmux *cmux, enum modem_cmux_event event)
239 {
240 	if (cmux->callback == NULL) {
241 		return;
242 	}
243 
244 	cmux->callback(cmux, event, cmux->user_data);
245 }
246 
modem_cmux_bus_callback(struct modem_pipe * pipe,enum modem_pipe_event event,void * user_data)247 static void modem_cmux_bus_callback(struct modem_pipe *pipe, enum modem_pipe_event event,
248 				    void *user_data)
249 {
250 	struct modem_cmux *cmux = (struct modem_cmux *)user_data;
251 
252 	switch (event) {
253 	case MODEM_PIPE_EVENT_RECEIVE_READY:
254 		k_work_schedule(&cmux->receive_work, K_NO_WAIT);
255 		break;
256 
257 	case MODEM_PIPE_EVENT_TRANSMIT_IDLE:
258 		k_work_schedule(&cmux->transmit_work, K_NO_WAIT);
259 		break;
260 
261 	default:
262 		break;
263 	}
264 }
265 
modem_cmux_transmit_frame(struct modem_cmux * cmux,const struct modem_cmux_frame * frame)266 static uint16_t modem_cmux_transmit_frame(struct modem_cmux *cmux,
267 					  const struct modem_cmux_frame *frame)
268 {
269 	uint8_t buf[MODEM_CMUX_FRAME_SIZE_MAX];
270 	uint8_t fcs;
271 	uint16_t space;
272 	uint16_t data_len;
273 	uint16_t buf_idx;
274 
275 	space = ring_buf_space_get(&cmux->transmit_rb) - MODEM_CMUX_FRAME_SIZE_MAX;
276 	data_len = MIN(space, frame->data_len);
277 
278 	/* SOF */
279 	buf[0] = 0xF9;
280 
281 	/* DLCI Address (Max 63) */
282 	buf[1] = 0x01 | (frame->cr << 1) | (frame->dlci_address << 2);
283 
284 	/* Frame type and poll/final */
285 	buf[2] = frame->type | (frame->pf << 4);
286 
287 	/* Data length */
288 	if (data_len > 127) {
289 		buf[3] = data_len << 1;
290 		buf[4] = data_len >> 7;
291 		buf_idx = 5;
292 	} else {
293 		buf[3] = 0x01 | (data_len << 1);
294 		buf_idx = 4;
295 	}
296 
297 	/* Compute FCS for the header (exclude SOF) */
298 	fcs = crc8_rohc(MODEM_CMUX_FCS_INIT_VALUE, &buf[1], (buf_idx - 1));
299 
300 	/* FCS final */
301 	if (frame->type == MODEM_CMUX_FRAME_TYPE_UIH) {
302 		fcs = 0xFF - fcs;
303 	} else {
304 		fcs = 0xFF - crc8_rohc(fcs, frame->data, data_len);
305 	}
306 
307 	/* Frame header */
308 	ring_buf_put(&cmux->transmit_rb, buf, buf_idx);
309 
310 	/* Data */
311 	ring_buf_put(&cmux->transmit_rb, frame->data, data_len);
312 
313 	/* FCS and EOF will be put on the same call */
314 	buf[0] = fcs;
315 	buf[1] = 0xF9;
316 	ring_buf_put(&cmux->transmit_rb, buf, 2);
317 	k_work_schedule(&cmux->transmit_work, K_NO_WAIT);
318 	return data_len;
319 }
320 
modem_cmux_transmit_cmd_frame(struct modem_cmux * cmux,const struct modem_cmux_frame * frame)321 static bool modem_cmux_transmit_cmd_frame(struct modem_cmux *cmux,
322 					  const struct modem_cmux_frame *frame)
323 {
324 	uint16_t space;
325 	struct modem_cmux_command *command;
326 
327 	k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
328 	space = ring_buf_space_get(&cmux->transmit_rb);
329 
330 	if (space < MODEM_CMUX_CMD_FRAME_SIZE_MAX) {
331 		k_mutex_unlock(&cmux->transmit_rb_lock);
332 		return false;
333 	}
334 
335 	modem_cmux_log_transmit_frame(frame);
336 	if (modem_cmux_wrap_command(&command, frame->data, frame->data_len) == 0) {
337 		modem_cmux_log_transmit_command(command);
338 	}
339 
340 	modem_cmux_transmit_frame(cmux, frame);
341 	k_mutex_unlock(&cmux->transmit_rb_lock);
342 	return true;
343 }
344 
modem_cmux_transmit_data_frame(struct modem_cmux * cmux,const struct modem_cmux_frame * frame)345 static int16_t modem_cmux_transmit_data_frame(struct modem_cmux *cmux,
346 					      const struct modem_cmux_frame *frame)
347 {
348 	uint16_t space;
349 	int ret;
350 
351 	k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
352 
353 	if (cmux->flow_control_on == false) {
354 		k_mutex_unlock(&cmux->transmit_rb_lock);
355 		return 0;
356 	}
357 
358 	space = ring_buf_space_get(&cmux->transmit_rb);
359 
360 	/*
361 	 * Two command frames are reserved for command channel, and we shall prefer
362 	 * waiting for more than MODEM_CMUX_DATA_FRAME_SIZE_MIN bytes available in the
363 	 * transmit buffer rather than transmitting a few bytes at a time. This avoids
364 	 * excessive wrapping overhead, since transmitting a single byte will require 8
365 	 * bytes of wrapping.
366 	 */
367 	if (space < ((MODEM_CMUX_CMD_FRAME_SIZE_MAX * 2) + MODEM_CMUX_DATA_FRAME_SIZE_MIN)) {
368 		k_mutex_unlock(&cmux->transmit_rb_lock);
369 		return -ENOMEM;
370 	}
371 
372 	modem_cmux_log_transmit_frame(frame);
373 	ret = modem_cmux_transmit_frame(cmux, frame);
374 	k_mutex_unlock(&cmux->transmit_rb_lock);
375 	return ret;
376 }
377 
modem_cmux_acknowledge_received_frame(struct modem_cmux * cmux)378 static void modem_cmux_acknowledge_received_frame(struct modem_cmux *cmux)
379 {
380 	struct modem_cmux_command *command;
381 	struct modem_cmux_frame frame;
382 	uint8_t data[MODEM_CMUX_CMD_DATA_SIZE_MAX];
383 
384 	if (sizeof(data) < cmux->frame.data_len) {
385 		LOG_WRN("Command acknowledge buffer overrun");
386 		return;
387 	}
388 
389 	memcpy(&frame, &cmux->frame, sizeof(cmux->frame));
390 	memcpy(data, cmux->frame.data, cmux->frame.data_len);
391 	modem_cmux_wrap_command(&command, data, cmux->frame.data_len);
392 	command->type.cr = 0;
393 	frame.data = data;
394 	frame.data_len = cmux->frame.data_len;
395 
396 	if (modem_cmux_transmit_cmd_frame(cmux, &frame) == false) {
397 		LOG_WRN("Command acknowledge buffer overrun");
398 	}
399 }
400 
modem_cmux_on_msc_command(struct modem_cmux * cmux,struct modem_cmux_command * command)401 static void modem_cmux_on_msc_command(struct modem_cmux *cmux, struct modem_cmux_command *command)
402 {
403 	if (command->type.cr) {
404 		modem_cmux_acknowledge_received_frame(cmux);
405 	}
406 }
407 
modem_cmux_on_fcon_command(struct modem_cmux * cmux)408 static void modem_cmux_on_fcon_command(struct modem_cmux *cmux)
409 {
410 	k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
411 	cmux->flow_control_on = true;
412 	k_mutex_unlock(&cmux->transmit_rb_lock);
413 	modem_cmux_acknowledge_received_frame(cmux);
414 }
415 
modem_cmux_on_fcoff_command(struct modem_cmux * cmux)416 static void modem_cmux_on_fcoff_command(struct modem_cmux *cmux)
417 {
418 	k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
419 	cmux->flow_control_on = false;
420 	k_mutex_unlock(&cmux->transmit_rb_lock);
421 	modem_cmux_acknowledge_received_frame(cmux);
422 }
423 
modem_cmux_on_cld_command(struct modem_cmux * cmux,struct modem_cmux_command * command)424 static void modem_cmux_on_cld_command(struct modem_cmux *cmux, struct modem_cmux_command *command)
425 {
426 	if (command->type.cr) {
427 		modem_cmux_acknowledge_received_frame(cmux);
428 	}
429 
430 	if (cmux->state != MODEM_CMUX_STATE_DISCONNECTING &&
431 	    cmux->state != MODEM_CMUX_STATE_CONNECTED) {
432 		LOG_WRN("Unexpected close down");
433 		return;
434 	}
435 
436 	if (cmux->state == MODEM_CMUX_STATE_DISCONNECTING) {
437 		k_work_cancel_delayable(&cmux->disconnect_work);
438 	}
439 
440 	cmux->state = MODEM_CMUX_STATE_DISCONNECTED;
441 	k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
442 	cmux->flow_control_on = false;
443 	k_mutex_unlock(&cmux->transmit_rb_lock);
444 
445 	modem_cmux_raise_event(cmux, MODEM_CMUX_EVENT_DISCONNECTED);
446 	k_event_clear(&cmux->event, MODEM_CMUX_EVENT_CONNECTED_BIT);
447 	k_event_post(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT);
448 }
449 
modem_cmux_on_control_frame_ua(struct modem_cmux * cmux)450 static void modem_cmux_on_control_frame_ua(struct modem_cmux *cmux)
451 {
452 	if (cmux->state != MODEM_CMUX_STATE_CONNECTING) {
453 		LOG_DBG("Unexpected UA frame");
454 		return;
455 	}
456 
457 	cmux->state = MODEM_CMUX_STATE_CONNECTED;
458 	k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
459 	cmux->flow_control_on = true;
460 	k_mutex_unlock(&cmux->transmit_rb_lock);
461 	k_work_cancel_delayable(&cmux->connect_work);
462 	modem_cmux_raise_event(cmux, MODEM_CMUX_EVENT_CONNECTED);
463 	k_event_clear(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT);
464 	k_event_post(&cmux->event, MODEM_CMUX_EVENT_CONNECTED_BIT);
465 }
466 
modem_cmux_on_control_frame_uih(struct modem_cmux * cmux)467 static void modem_cmux_on_control_frame_uih(struct modem_cmux *cmux)
468 {
469 	struct modem_cmux_command *command;
470 
471 	if ((cmux->state != MODEM_CMUX_STATE_CONNECTED) &&
472 	    (cmux->state != MODEM_CMUX_STATE_DISCONNECTING)) {
473 		LOG_DBG("Unexpected UIH frame");
474 		return;
475 	}
476 
477 	if (modem_cmux_wrap_command(&command, cmux->frame.data, cmux->frame.data_len) < 0) {
478 		LOG_WRN("Invalid command");
479 		return;
480 	}
481 
482 	modem_cmux_log_received_command(command);
483 
484 	switch (command->type.value) {
485 	case MODEM_CMUX_COMMAND_CLD:
486 		modem_cmux_on_cld_command(cmux, command);
487 		break;
488 
489 	case MODEM_CMUX_COMMAND_MSC:
490 		modem_cmux_on_msc_command(cmux, command);
491 		break;
492 
493 	case MODEM_CMUX_COMMAND_FCON:
494 		modem_cmux_on_fcon_command(cmux);
495 		break;
496 
497 	case MODEM_CMUX_COMMAND_FCOFF:
498 		modem_cmux_on_fcoff_command(cmux);
499 		break;
500 
501 	default:
502 		LOG_DBG("Unknown control command");
503 		break;
504 	}
505 }
506 
modem_cmux_connect_response_transmit(struct modem_cmux * cmux)507 static void modem_cmux_connect_response_transmit(struct modem_cmux *cmux)
508 {
509 	if (cmux == NULL) {
510 		return;
511 	}
512 
513 	struct modem_cmux_frame frame = {
514 		.dlci_address = cmux->frame.dlci_address,
515 		.cr = cmux->frame.cr,
516 		.pf = cmux->frame.pf,
517 		.type = MODEM_CMUX_FRAME_TYPE_UA,
518 		.data = NULL,
519 		.data_len = 0,
520 	};
521 
522 	LOG_DBG("SABM/DISC request state send ack");
523 	modem_cmux_transmit_cmd_frame(cmux, &frame);
524 }
525 
modem_cmux_on_control_frame_sabm(struct modem_cmux * cmux)526 static void modem_cmux_on_control_frame_sabm(struct modem_cmux *cmux)
527 {
528 	modem_cmux_connect_response_transmit(cmux);
529 
530 	if ((cmux->state == MODEM_CMUX_STATE_CONNECTED) ||
531 	    (cmux->state == MODEM_CMUX_STATE_DISCONNECTING)) {
532 		LOG_DBG("Connect request not accepted");
533 		return;
534 	}
535 
536 	cmux->state = MODEM_CMUX_STATE_CONNECTED;
537 	k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
538 	cmux->flow_control_on = true;
539 	k_mutex_unlock(&cmux->transmit_rb_lock);
540 	modem_cmux_raise_event(cmux, MODEM_CMUX_EVENT_CONNECTED);
541 	k_event_clear(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT);
542 	k_event_post(&cmux->event, MODEM_CMUX_EVENT_CONNECTED_BIT);
543 }
544 
modem_cmux_on_control_frame(struct modem_cmux * cmux)545 static void modem_cmux_on_control_frame(struct modem_cmux *cmux)
546 {
547 	modem_cmux_log_received_frame(&cmux->frame);
548 
549 	switch (cmux->frame.type) {
550 	case MODEM_CMUX_FRAME_TYPE_UA:
551 		modem_cmux_on_control_frame_ua(cmux);
552 		break;
553 
554 	case MODEM_CMUX_FRAME_TYPE_UIH:
555 		modem_cmux_on_control_frame_uih(cmux);
556 		break;
557 
558 	case MODEM_CMUX_FRAME_TYPE_SABM:
559 		modem_cmux_on_control_frame_sabm(cmux);
560 		break;
561 
562 	default:
563 		LOG_WRN("Unknown %s frame type", "control");
564 		break;
565 	}
566 }
567 
modem_cmux_find_dlci(struct modem_cmux * cmux)568 static struct modem_cmux_dlci *modem_cmux_find_dlci(struct modem_cmux *cmux)
569 {
570 	sys_snode_t *node;
571 	struct modem_cmux_dlci *dlci;
572 
573 	SYS_SLIST_FOR_EACH_NODE(&cmux->dlcis, node) {
574 		dlci = (struct modem_cmux_dlci *)node;
575 
576 		if (dlci->dlci_address == cmux->frame.dlci_address) {
577 			return dlci;
578 		}
579 	}
580 
581 	return NULL;
582 }
583 
modem_cmux_on_dlci_frame_ua(struct modem_cmux_dlci * dlci)584 static void modem_cmux_on_dlci_frame_ua(struct modem_cmux_dlci *dlci)
585 {
586 	switch (dlci->state) {
587 	case MODEM_CMUX_DLCI_STATE_OPENING:
588 		dlci->state = MODEM_CMUX_DLCI_STATE_OPEN;
589 		modem_pipe_notify_opened(&dlci->pipe);
590 		k_work_cancel_delayable(&dlci->open_work);
591 		k_mutex_lock(&dlci->receive_rb_lock, K_FOREVER);
592 		ring_buf_reset(&dlci->receive_rb);
593 		k_mutex_unlock(&dlci->receive_rb_lock);
594 		break;
595 
596 	case MODEM_CMUX_DLCI_STATE_CLOSING:
597 		dlci->state = MODEM_CMUX_DLCI_STATE_CLOSED;
598 		modem_pipe_notify_closed(&dlci->pipe);
599 		k_work_cancel_delayable(&dlci->close_work);
600 		break;
601 
602 	default:
603 		LOG_DBG("Unexpected UA frame");
604 		break;
605 	}
606 }
607 
modem_cmux_on_dlci_frame_uih(struct modem_cmux_dlci * dlci)608 static void modem_cmux_on_dlci_frame_uih(struct modem_cmux_dlci *dlci)
609 {
610 	struct modem_cmux *cmux = dlci->cmux;
611 	uint32_t written;
612 
613 	if (dlci->state != MODEM_CMUX_DLCI_STATE_OPEN) {
614 		LOG_DBG("Unexpected UIH frame");
615 		return;
616 	}
617 
618 	k_mutex_lock(&dlci->receive_rb_lock, K_FOREVER);
619 	written = ring_buf_put(&dlci->receive_rb, cmux->frame.data, cmux->frame.data_len);
620 	k_mutex_unlock(&dlci->receive_rb_lock);
621 	if (written != cmux->frame.data_len) {
622 		LOG_WRN("DLCI %u receive buffer overrun (dropped %u out of %u bytes)",
623 			dlci->dlci_address, cmux->frame.data_len - written, cmux->frame.data_len);
624 	}
625 	modem_pipe_notify_receive_ready(&dlci->pipe);
626 }
627 
modem_cmux_on_dlci_frame_sabm(struct modem_cmux_dlci * dlci)628 static void modem_cmux_on_dlci_frame_sabm(struct modem_cmux_dlci *dlci)
629 {
630 	struct modem_cmux *cmux = dlci->cmux;
631 
632 	modem_cmux_connect_response_transmit(cmux);
633 
634 	if (dlci->state == MODEM_CMUX_DLCI_STATE_OPEN) {
635 		LOG_DBG("Unexpected SABM frame");
636 		return;
637 	}
638 
639 	dlci->state = MODEM_CMUX_DLCI_STATE_OPEN;
640 	modem_pipe_notify_opened(&dlci->pipe);
641 	k_mutex_lock(&dlci->receive_rb_lock, K_FOREVER);
642 	ring_buf_reset(&dlci->receive_rb);
643 	k_mutex_unlock(&dlci->receive_rb_lock);
644 }
645 
modem_cmux_on_dlci_frame_disc(struct modem_cmux_dlci * dlci)646 static void modem_cmux_on_dlci_frame_disc(struct modem_cmux_dlci *dlci)
647 {
648 	struct modem_cmux *cmux = dlci->cmux;
649 
650 	modem_cmux_connect_response_transmit(cmux);
651 
652 	if (dlci->state != MODEM_CMUX_DLCI_STATE_OPEN) {
653 		LOG_DBG("Unexpected Disc frame");
654 		return;
655 	}
656 
657 	dlci->state = MODEM_CMUX_DLCI_STATE_CLOSED;
658 	modem_pipe_notify_closed(&dlci->pipe);
659 }
660 
modem_cmux_on_dlci_frame(struct modem_cmux * cmux)661 static void modem_cmux_on_dlci_frame(struct modem_cmux *cmux)
662 {
663 	struct modem_cmux_dlci *dlci;
664 
665 	modem_cmux_log_received_frame(&cmux->frame);
666 
667 	dlci = modem_cmux_find_dlci(cmux);
668 	if (dlci == NULL) {
669 		LOG_WRN("Ignoring frame intended for unconfigured DLCI %u.",
670 			cmux->frame.dlci_address);
671 		return;
672 	}
673 
674 	switch (cmux->frame.type) {
675 	case MODEM_CMUX_FRAME_TYPE_UA:
676 		modem_cmux_on_dlci_frame_ua(dlci);
677 		break;
678 
679 	case MODEM_CMUX_FRAME_TYPE_UIH:
680 		modem_cmux_on_dlci_frame_uih(dlci);
681 		break;
682 
683 	case MODEM_CMUX_FRAME_TYPE_SABM:
684 		modem_cmux_on_dlci_frame_sabm(dlci);
685 		break;
686 
687 	case MODEM_CMUX_FRAME_TYPE_DISC:
688 		modem_cmux_on_dlci_frame_disc(dlci);
689 		break;
690 
691 	default:
692 		LOG_WRN("Unknown %s frame type", "DLCI");
693 		break;
694 	}
695 }
696 
modem_cmux_on_frame(struct modem_cmux * cmux)697 static void modem_cmux_on_frame(struct modem_cmux *cmux)
698 {
699 #if CONFIG_MODEM_STATS
700 	modem_cmux_advertise_receive_buf_stats(cmux);
701 #endif
702 
703 	if (cmux->frame.dlci_address == 0) {
704 		modem_cmux_on_control_frame(cmux);
705 	} else {
706 		modem_cmux_on_dlci_frame(cmux);
707 	}
708 }
709 
modem_cmux_drop_frame(struct modem_cmux * cmux)710 static void modem_cmux_drop_frame(struct modem_cmux *cmux)
711 {
712 #if CONFIG_MODEM_STATS
713 	modem_cmux_advertise_receive_buf_stats(cmux);
714 #endif
715 
716 	LOG_WRN("Dropped frame");
717 	cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_SOF;
718 
719 #if defined(CONFIG_MODEM_CMUX_LOG_LEVEL_DBG)
720 	struct modem_cmux_frame *frame = &cmux->frame;
721 
722 	frame->data = cmux->receive_buf;
723 	modem_cmux_log_frame(frame, "dropped", MIN(frame->data_len, cmux->receive_buf_size));
724 #endif
725 }
726 
modem_cmux_process_received_byte(struct modem_cmux * cmux,uint8_t byte)727 static void modem_cmux_process_received_byte(struct modem_cmux *cmux, uint8_t byte)
728 {
729 	uint8_t fcs;
730 
731 	switch (cmux->receive_state) {
732 	case MODEM_CMUX_RECEIVE_STATE_SOF:
733 		if (byte == 0xF9) {
734 			cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_RESYNC;
735 			break;
736 		}
737 
738 		break;
739 
740 	case MODEM_CMUX_RECEIVE_STATE_RESYNC:
741 		/*
742 		 * Allow any number of consecutive flags (0xF9).
743 		 * 0xF9 could also be a valid address field for DLCI 62.
744 		 */
745 		if (byte == 0xF9) {
746 			break;
747 		}
748 
749 		__fallthrough;
750 
751 	case MODEM_CMUX_RECEIVE_STATE_ADDRESS:
752 		/* Initialize */
753 		cmux->receive_buf_len = 0;
754 		cmux->frame_header_len = 0;
755 
756 		/* Store header for FCS */
757 		cmux->frame_header[cmux->frame_header_len] = byte;
758 		cmux->frame_header_len++;
759 
760 		/* Get CR */
761 		cmux->frame.cr = (byte & 0x02) ? true : false;
762 
763 		/* Get DLCI address */
764 		cmux->frame.dlci_address = (byte >> 2) & 0x3F;
765 
766 		/* Await control */
767 		cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_CONTROL;
768 		break;
769 
770 	case MODEM_CMUX_RECEIVE_STATE_CONTROL:
771 		/* Store header for FCS */
772 		cmux->frame_header[cmux->frame_header_len] = byte;
773 		cmux->frame_header_len++;
774 
775 		/* Get PF */
776 		cmux->frame.pf = (byte & MODEM_CMUX_PF) ? true : false;
777 
778 		/* Get frame type */
779 		cmux->frame.type = byte & (~MODEM_CMUX_PF);
780 
781 		/* Await data length */
782 		cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_LENGTH;
783 		break;
784 
785 	case MODEM_CMUX_RECEIVE_STATE_LENGTH:
786 		/* Store header for FCS */
787 		cmux->frame_header[cmux->frame_header_len] = byte;
788 		cmux->frame_header_len++;
789 
790 		/* Get first 7 bits of data length */
791 		cmux->frame.data_len = (byte >> 1);
792 
793 		/* Check if length field continues */
794 		if ((byte & MODEM_CMUX_EA) == 0) {
795 			/* Await continued length field */
796 			cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_LENGTH_CONT;
797 			break;
798 		}
799 
800 		/* Check if no data field */
801 		if (cmux->frame.data_len == 0) {
802 			/* Await FCS */
803 			cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_FCS;
804 			break;
805 		}
806 
807 		/* Await data */
808 		cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_DATA;
809 		break;
810 
811 	case MODEM_CMUX_RECEIVE_STATE_LENGTH_CONT:
812 		/* Store header for FCS */
813 		cmux->frame_header[cmux->frame_header_len] = byte;
814 		cmux->frame_header_len++;
815 
816 		/* Get last 8 bits of data length */
817 		cmux->frame.data_len |= ((uint16_t)byte) << 7;
818 
819 		if (cmux->frame.data_len > cmux->receive_buf_size) {
820 			LOG_ERR("Indicated frame data length %u exceeds receive buffer size %u",
821 				cmux->frame.data_len, cmux->receive_buf_size);
822 
823 			cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_DROP;
824 			break;
825 		}
826 
827 		/* Await data */
828 		cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_DATA;
829 		break;
830 
831 	case MODEM_CMUX_RECEIVE_STATE_DATA:
832 		/* Copy byte to data */
833 		if (cmux->receive_buf_len < cmux->receive_buf_size) {
834 			cmux->receive_buf[cmux->receive_buf_len] = byte;
835 		}
836 		cmux->receive_buf_len++;
837 
838 		/* Check if datalen reached */
839 		if (cmux->frame.data_len == cmux->receive_buf_len) {
840 			/* Await FCS */
841 			cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_FCS;
842 		}
843 
844 		break;
845 
846 	case MODEM_CMUX_RECEIVE_STATE_FCS:
847 		if (cmux->receive_buf_len > cmux->receive_buf_size) {
848 			LOG_WRN("Receive buffer overrun (%u > %u)",
849 				cmux->receive_buf_len, cmux->receive_buf_size);
850 			cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_DROP;
851 			break;
852 		}
853 
854 		/* Compute FCS */
855 		fcs = crc8_rohc(MODEM_CMUX_FCS_INIT_VALUE, cmux->frame_header,
856 				cmux->frame_header_len);
857 		if (cmux->frame.type == MODEM_CMUX_FRAME_TYPE_UIH) {
858 			fcs = 0xFF - fcs;
859 		} else {
860 			fcs = 0xFF - crc8_rohc(fcs, cmux->frame.data, cmux->frame.data_len);
861 		}
862 
863 		/* Validate FCS */
864 		if (fcs != byte) {
865 			LOG_WRN("Frame FCS error");
866 
867 			/* Drop frame */
868 			cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_DROP;
869 			break;
870 		}
871 
872 		cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_EOF;
873 		break;
874 
875 	case MODEM_CMUX_RECEIVE_STATE_DROP:
876 		modem_cmux_drop_frame(cmux);
877 		break;
878 
879 	case MODEM_CMUX_RECEIVE_STATE_EOF:
880 		/* Validate byte is EOF */
881 		if (byte != 0xF9) {
882 			/* Unexpected byte */
883 			modem_cmux_drop_frame(cmux);
884 			break;
885 		}
886 
887 		/* Process frame */
888 		cmux->frame.data = cmux->receive_buf;
889 		modem_cmux_on_frame(cmux);
890 
891 		/* Await start of next frame */
892 		cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_SOF;
893 		break;
894 
895 	default:
896 		break;
897 	}
898 }
899 
modem_cmux_receive_handler(struct k_work * item)900 static void modem_cmux_receive_handler(struct k_work *item)
901 {
902 	struct k_work_delayable *dwork = k_work_delayable_from_work(item);
903 	struct modem_cmux *cmux = CONTAINER_OF(dwork, struct modem_cmux, receive_work);
904 	int ret;
905 
906 	/* Receive data from pipe */
907 	ret = modem_pipe_receive(cmux->pipe, cmux->work_buf, sizeof(cmux->work_buf));
908 	if (ret < 1) {
909 		if (ret < 0) {
910 			LOG_ERR("Pipe receiving error: %d", ret);
911 		}
912 		return;
913 	}
914 
915 	/* Process received data */
916 	for (int i = 0; i < ret; i++) {
917 		modem_cmux_process_received_byte(cmux, cmux->work_buf[i]);
918 	}
919 
920 	/* Reschedule received work */
921 	k_work_schedule(&cmux->receive_work, K_NO_WAIT);
922 }
923 
modem_cmux_dlci_notify_transmit_idle(struct modem_cmux * cmux)924 static void modem_cmux_dlci_notify_transmit_idle(struct modem_cmux *cmux)
925 {
926 	sys_snode_t *node;
927 	struct modem_cmux_dlci *dlci;
928 
929 	SYS_SLIST_FOR_EACH_NODE(&cmux->dlcis, node) {
930 		dlci = (struct modem_cmux_dlci *)node;
931 		modem_pipe_notify_transmit_idle(&dlci->pipe);
932 	}
933 }
934 
modem_cmux_transmit_handler(struct k_work * item)935 static void modem_cmux_transmit_handler(struct k_work *item)
936 {
937 	struct k_work_delayable *dwork = k_work_delayable_from_work(item);
938 	struct modem_cmux *cmux = CONTAINER_OF(dwork, struct modem_cmux, transmit_work);
939 	uint8_t *reserved;
940 	uint32_t reserved_size;
941 	int ret;
942 	bool transmit_rb_empty;
943 
944 	k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
945 
946 #if CONFIG_MODEM_STATS
947 	modem_cmux_advertise_transmit_buf_stats(cmux);
948 #endif
949 
950 	while (true) {
951 		transmit_rb_empty = ring_buf_is_empty(&cmux->transmit_rb);
952 
953 		if (transmit_rb_empty) {
954 			break;
955 		}
956 
957 		reserved_size = ring_buf_get_claim(&cmux->transmit_rb, &reserved, UINT32_MAX);
958 
959 		ret = modem_pipe_transmit(cmux->pipe, reserved, reserved_size);
960 		if (ret < 0) {
961 			ring_buf_get_finish(&cmux->transmit_rb, 0);
962 			if (ret != -EPERM) {
963 				LOG_ERR("Failed to %s %u bytes. (%d)",
964 					"transmit", reserved_size, ret);
965 			}
966 			break;
967 		}
968 
969 		ring_buf_get_finish(&cmux->transmit_rb, (uint32_t)ret);
970 
971 		if (ret < reserved_size) {
972 			LOG_DBG("Transmitted only %u out of %u bytes at once.", ret, reserved_size);
973 			break;
974 		}
975 	}
976 
977 	k_mutex_unlock(&cmux->transmit_rb_lock);
978 
979 	if (transmit_rb_empty) {
980 		modem_cmux_dlci_notify_transmit_idle(cmux);
981 	}
982 }
983 
modem_cmux_connect_handler(struct k_work * item)984 static void modem_cmux_connect_handler(struct k_work *item)
985 {
986 	struct k_work_delayable *dwork;
987 	struct modem_cmux *cmux;
988 
989 	if (item == NULL) {
990 		return;
991 	}
992 
993 	dwork = k_work_delayable_from_work(item);
994 	cmux = CONTAINER_OF(dwork, struct modem_cmux, connect_work);
995 
996 	cmux->state = MODEM_CMUX_STATE_CONNECTING;
997 
998 	static const struct modem_cmux_frame frame = {
999 		.dlci_address = 0,
1000 		.cr = true,
1001 		.pf = true,
1002 		.type = MODEM_CMUX_FRAME_TYPE_SABM,
1003 		.data = NULL,
1004 		.data_len = 0,
1005 	};
1006 
1007 	modem_cmux_transmit_cmd_frame(cmux, &frame);
1008 	k_work_schedule(&cmux->connect_work, MODEM_CMUX_T1_TIMEOUT);
1009 }
1010 
modem_cmux_disconnect_handler(struct k_work * item)1011 static void modem_cmux_disconnect_handler(struct k_work *item)
1012 {
1013 	struct k_work_delayable *dwork = k_work_delayable_from_work(item);
1014 	struct modem_cmux *cmux = CONTAINER_OF(dwork, struct modem_cmux, disconnect_work);
1015 	struct modem_cmux_command *command;
1016 	uint8_t data[2];
1017 
1018 	cmux->state = MODEM_CMUX_STATE_DISCONNECTING;
1019 
1020 	command = modem_cmux_command_wrap(data);
1021 	command->type.ea = 1;
1022 	command->type.cr = 1;
1023 	command->type.value = MODEM_CMUX_COMMAND_CLD;
1024 	command->length.ea = 1;
1025 	command->length.value = 0;
1026 
1027 	struct modem_cmux_frame frame = {
1028 		.dlci_address = 0,
1029 		.cr = true,
1030 		.pf = false,
1031 		.type = MODEM_CMUX_FRAME_TYPE_UIH,
1032 		.data = data,
1033 		.data_len = sizeof(data),
1034 	};
1035 
1036 	/* Transmit close down command */
1037 	modem_cmux_transmit_cmd_frame(cmux, &frame);
1038 	k_work_schedule(&cmux->disconnect_work, MODEM_CMUX_T1_TIMEOUT);
1039 }
1040 
1041 #if CONFIG_MODEM_STATS
modem_cmux_dlci_get_receive_buf_length(struct modem_cmux_dlci * dlci)1042 static uint32_t modem_cmux_dlci_get_receive_buf_length(struct modem_cmux_dlci *dlci)
1043 {
1044 	return ring_buf_size_get(&dlci->receive_rb);
1045 }
1046 
modem_cmux_dlci_get_receive_buf_size(struct modem_cmux_dlci * dlci)1047 static uint32_t modem_cmux_dlci_get_receive_buf_size(struct modem_cmux_dlci *dlci)
1048 {
1049 	return ring_buf_capacity_get(&dlci->receive_rb);
1050 }
1051 
modem_cmux_dlci_init_buf_stats(struct modem_cmux_dlci * dlci)1052 static void modem_cmux_dlci_init_buf_stats(struct modem_cmux_dlci *dlci)
1053 {
1054 	uint32_t size;
1055 	char name[sizeof("dlci_xxxxx_rx")];
1056 
1057 	size = modem_cmux_dlci_get_receive_buf_size(dlci);
1058 	snprintk(name, sizeof(name), "dlci_%u_rx", dlci->dlci_address);
1059 	modem_stats_buffer_init(&dlci->receive_buf_stats, name, size);
1060 }
1061 
modem_cmux_dlci_advertise_receive_buf_stat(struct modem_cmux_dlci * dlci)1062 static void modem_cmux_dlci_advertise_receive_buf_stat(struct modem_cmux_dlci *dlci)
1063 {
1064 	uint32_t length;
1065 
1066 	length = modem_cmux_dlci_get_receive_buf_length(dlci);
1067 	modem_stats_buffer_advertise_length(&dlci->receive_buf_stats, length);
1068 }
1069 #endif
1070 
modem_cmux_dlci_pipe_api_open(void * data)1071 static int modem_cmux_dlci_pipe_api_open(void *data)
1072 {
1073 	struct modem_cmux_dlci *dlci = (struct modem_cmux_dlci *)data;
1074 	struct modem_cmux *cmux = dlci->cmux;
1075 	int ret = 0;
1076 
1077 	K_SPINLOCK(&cmux->work_lock) {
1078 		if (!cmux->attached) {
1079 			ret = -EPERM;
1080 			K_SPINLOCK_BREAK;
1081 		}
1082 
1083 		if (k_work_delayable_is_pending(&dlci->open_work) == true) {
1084 			ret = -EBUSY;
1085 			K_SPINLOCK_BREAK;
1086 		}
1087 
1088 		k_work_schedule(&dlci->open_work, K_NO_WAIT);
1089 	}
1090 
1091 	return ret;
1092 }
1093 
modem_cmux_dlci_pipe_api_transmit(void * data,const uint8_t * buf,size_t size)1094 static int modem_cmux_dlci_pipe_api_transmit(void *data, const uint8_t *buf, size_t size)
1095 {
1096 	struct modem_cmux_dlci *dlci = (struct modem_cmux_dlci *)data;
1097 	struct modem_cmux *cmux = dlci->cmux;
1098 	int ret;
1099 
1100 	K_SPINLOCK(&cmux->work_lock) {
1101 		if (!cmux->attached) {
1102 			ret = -EPERM;
1103 			K_SPINLOCK_BREAK;
1104 		}
1105 
1106 		struct modem_cmux_frame frame = {
1107 			.dlci_address = dlci->dlci_address,
1108 			.cr = true,
1109 			.pf = false,
1110 			.type = MODEM_CMUX_FRAME_TYPE_UIH,
1111 			.data = buf,
1112 			.data_len = size,
1113 		};
1114 
1115 		ret = modem_cmux_transmit_data_frame(cmux, &frame);
1116 	}
1117 
1118 	return ret;
1119 }
1120 
modem_cmux_dlci_pipe_api_receive(void * data,uint8_t * buf,size_t size)1121 static int modem_cmux_dlci_pipe_api_receive(void *data, uint8_t *buf, size_t size)
1122 {
1123 	struct modem_cmux_dlci *dlci = (struct modem_cmux_dlci *)data;
1124 	uint32_t ret;
1125 
1126 	k_mutex_lock(&dlci->receive_rb_lock, K_FOREVER);
1127 
1128 #if CONFIG_MODEM_STATS
1129 	modem_cmux_dlci_advertise_receive_buf_stat(dlci);
1130 #endif
1131 
1132 	ret = ring_buf_get(&dlci->receive_rb, buf, size);
1133 	k_mutex_unlock(&dlci->receive_rb_lock);
1134 	return ret;
1135 }
1136 
modem_cmux_dlci_pipe_api_close(void * data)1137 static int modem_cmux_dlci_pipe_api_close(void *data)
1138 {
1139 	struct modem_cmux_dlci *dlci = (struct modem_cmux_dlci *)data;
1140 	struct modem_cmux *cmux = dlci->cmux;
1141 	int ret = 0;
1142 
1143 	K_SPINLOCK(&cmux->work_lock) {
1144 		if (!cmux->attached) {
1145 			ret = -EPERM;
1146 			K_SPINLOCK_BREAK;
1147 		}
1148 
1149 		if (k_work_delayable_is_pending(&dlci->close_work) == true) {
1150 			ret = -EBUSY;
1151 			K_SPINLOCK_BREAK;
1152 		}
1153 
1154 		k_work_schedule(&dlci->close_work, K_NO_WAIT);
1155 	}
1156 
1157 	return ret;
1158 }
1159 
1160 static const struct modem_pipe_api modem_cmux_dlci_pipe_api = {
1161 	.open = modem_cmux_dlci_pipe_api_open,
1162 	.transmit = modem_cmux_dlci_pipe_api_transmit,
1163 	.receive = modem_cmux_dlci_pipe_api_receive,
1164 	.close = modem_cmux_dlci_pipe_api_close,
1165 };
1166 
modem_cmux_dlci_open_handler(struct k_work * item)1167 static void modem_cmux_dlci_open_handler(struct k_work *item)
1168 {
1169 	struct k_work_delayable *dwork;
1170 	struct modem_cmux_dlci *dlci;
1171 
1172 	if (item == NULL) {
1173 		return;
1174 	}
1175 
1176 	dwork = k_work_delayable_from_work(item);
1177 	dlci = CONTAINER_OF(dwork, struct modem_cmux_dlci, open_work);
1178 
1179 	dlci->state = MODEM_CMUX_DLCI_STATE_OPENING;
1180 
1181 	struct modem_cmux_frame frame = {
1182 		.dlci_address = dlci->dlci_address,
1183 		.cr = true,
1184 		.pf = true,
1185 		.type = MODEM_CMUX_FRAME_TYPE_SABM,
1186 		.data = NULL,
1187 		.data_len = 0,
1188 	};
1189 
1190 	modem_cmux_transmit_cmd_frame(dlci->cmux, &frame);
1191 	k_work_schedule(&dlci->open_work, MODEM_CMUX_T1_TIMEOUT);
1192 }
1193 
modem_cmux_dlci_close_handler(struct k_work * item)1194 static void modem_cmux_dlci_close_handler(struct k_work *item)
1195 {
1196 	struct k_work_delayable *dwork;
1197 	struct modem_cmux_dlci *dlci;
1198 	struct modem_cmux *cmux;
1199 
1200 	if (item == NULL) {
1201 		return;
1202 	}
1203 
1204 	dwork = k_work_delayable_from_work(item);
1205 	dlci = CONTAINER_OF(dwork, struct modem_cmux_dlci, close_work);
1206 	cmux = dlci->cmux;
1207 
1208 	dlci->state = MODEM_CMUX_DLCI_STATE_CLOSING;
1209 
1210 	struct modem_cmux_frame frame = {
1211 		.dlci_address = dlci->dlci_address,
1212 		.cr = true,
1213 		.pf = true,
1214 		.type = MODEM_CMUX_FRAME_TYPE_DISC,
1215 		.data = NULL,
1216 		.data_len = 0,
1217 	};
1218 
1219 	modem_cmux_transmit_cmd_frame(cmux, &frame);
1220 	k_work_schedule(&dlci->close_work, MODEM_CMUX_T1_TIMEOUT);
1221 }
1222 
modem_cmux_dlci_pipes_release(struct modem_cmux * cmux)1223 static void modem_cmux_dlci_pipes_release(struct modem_cmux *cmux)
1224 {
1225 	sys_snode_t *node;
1226 	struct modem_cmux_dlci *dlci;
1227 	struct k_work_sync sync;
1228 
1229 	SYS_SLIST_FOR_EACH_NODE(&cmux->dlcis, node) {
1230 		dlci = (struct modem_cmux_dlci *)node;
1231 		modem_pipe_notify_closed(&dlci->pipe);
1232 		k_work_cancel_delayable_sync(&dlci->open_work, &sync);
1233 		k_work_cancel_delayable_sync(&dlci->close_work, &sync);
1234 	}
1235 }
1236 
modem_cmux_init(struct modem_cmux * cmux,const struct modem_cmux_config * config)1237 void modem_cmux_init(struct modem_cmux *cmux, const struct modem_cmux_config *config)
1238 {
1239 	__ASSERT_NO_MSG(cmux != NULL);
1240 	__ASSERT_NO_MSG(config != NULL);
1241 	__ASSERT_NO_MSG(config->receive_buf != NULL);
1242 	__ASSERT_NO_MSG(config->receive_buf_size >= 126);
1243 	__ASSERT_NO_MSG(config->transmit_buf != NULL);
1244 	__ASSERT_NO_MSG(config->transmit_buf_size >= 148);
1245 
1246 	memset(cmux, 0x00, sizeof(*cmux));
1247 	cmux->callback = config->callback;
1248 	cmux->user_data = config->user_data;
1249 	cmux->receive_buf = config->receive_buf;
1250 	cmux->receive_buf_size = config->receive_buf_size;
1251 	sys_slist_init(&cmux->dlcis);
1252 	cmux->state = MODEM_CMUX_STATE_DISCONNECTED;
1253 	ring_buf_init(&cmux->transmit_rb, config->transmit_buf_size, config->transmit_buf);
1254 	k_mutex_init(&cmux->transmit_rb_lock);
1255 	k_work_init_delayable(&cmux->receive_work, modem_cmux_receive_handler);
1256 	k_work_init_delayable(&cmux->transmit_work, modem_cmux_transmit_handler);
1257 	k_work_init_delayable(&cmux->connect_work, modem_cmux_connect_handler);
1258 	k_work_init_delayable(&cmux->disconnect_work, modem_cmux_disconnect_handler);
1259 	k_event_init(&cmux->event);
1260 	k_event_clear(&cmux->event, MODEM_CMUX_EVENT_CONNECTED_BIT);
1261 	k_event_post(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT);
1262 
1263 #if CONFIG_MODEM_STATS
1264 	modem_cmux_init_buf_stats(cmux);
1265 #endif
1266 }
1267 
modem_cmux_dlci_init(struct modem_cmux * cmux,struct modem_cmux_dlci * dlci,const struct modem_cmux_dlci_config * config)1268 struct modem_pipe *modem_cmux_dlci_init(struct modem_cmux *cmux, struct modem_cmux_dlci *dlci,
1269 					const struct modem_cmux_dlci_config *config)
1270 {
1271 	__ASSERT_NO_MSG(cmux != NULL);
1272 	__ASSERT_NO_MSG(dlci != NULL);
1273 	__ASSERT_NO_MSG(config != NULL);
1274 	__ASSERT_NO_MSG(config->dlci_address < 64);
1275 	__ASSERT_NO_MSG(config->receive_buf != NULL);
1276 	__ASSERT_NO_MSG(config->receive_buf_size >= 126);
1277 
1278 	memset(dlci, 0x00, sizeof(*dlci));
1279 	dlci->cmux = cmux;
1280 	dlci->dlci_address = config->dlci_address;
1281 	ring_buf_init(&dlci->receive_rb, config->receive_buf_size, config->receive_buf);
1282 	k_mutex_init(&dlci->receive_rb_lock);
1283 	modem_pipe_init(&dlci->pipe, dlci, &modem_cmux_dlci_pipe_api);
1284 	k_work_init_delayable(&dlci->open_work, modem_cmux_dlci_open_handler);
1285 	k_work_init_delayable(&dlci->close_work, modem_cmux_dlci_close_handler);
1286 	dlci->state = MODEM_CMUX_DLCI_STATE_CLOSED;
1287 	sys_slist_append(&dlci->cmux->dlcis, &dlci->node);
1288 
1289 #if CONFIG_MODEM_STATS
1290 	modem_cmux_dlci_init_buf_stats(dlci);
1291 #endif
1292 
1293 	return &dlci->pipe;
1294 }
1295 
modem_cmux_attach(struct modem_cmux * cmux,struct modem_pipe * pipe)1296 int modem_cmux_attach(struct modem_cmux *cmux, struct modem_pipe *pipe)
1297 {
1298 	if (cmux->pipe != NULL) {
1299 		return -EALREADY;
1300 	}
1301 
1302 	cmux->pipe = pipe;
1303 	ring_buf_reset(&cmux->transmit_rb);
1304 	cmux->receive_state = MODEM_CMUX_RECEIVE_STATE_SOF;
1305 	modem_pipe_attach(cmux->pipe, modem_cmux_bus_callback, cmux);
1306 
1307 	K_SPINLOCK(&cmux->work_lock) {
1308 		cmux->attached = true;
1309 	}
1310 
1311 	return 0;
1312 }
1313 
modem_cmux_connect(struct modem_cmux * cmux)1314 int modem_cmux_connect(struct modem_cmux *cmux)
1315 {
1316 	int ret;
1317 
1318 	ret = modem_cmux_connect_async(cmux);
1319 	if (ret < 0) {
1320 		return ret;
1321 	}
1322 
1323 	if (k_event_wait(&cmux->event, MODEM_CMUX_EVENT_CONNECTED_BIT, false,
1324 			 MODEM_CMUX_T2_TIMEOUT) == 0) {
1325 		return -EAGAIN;
1326 	}
1327 
1328 	return 0;
1329 }
1330 
modem_cmux_connect_async(struct modem_cmux * cmux)1331 int modem_cmux_connect_async(struct modem_cmux *cmux)
1332 {
1333 	int ret;
1334 
1335 	if (k_event_test(&cmux->event, MODEM_CMUX_EVENT_CONNECTED_BIT)) {
1336 		return -EALREADY;
1337 	}
1338 
1339 	K_SPINLOCK(&cmux->work_lock) {
1340 		if (!cmux->attached) {
1341 			ret = -EPERM;
1342 			K_SPINLOCK_BREAK;
1343 		}
1344 
1345 		if (k_work_delayable_is_pending(&cmux->connect_work) == false) {
1346 			k_work_schedule(&cmux->connect_work, K_NO_WAIT);
1347 		}
1348 
1349 		ret = 0;
1350 	}
1351 
1352 	return ret;
1353 }
1354 
modem_cmux_disconnect(struct modem_cmux * cmux)1355 int modem_cmux_disconnect(struct modem_cmux *cmux)
1356 {
1357 	int ret;
1358 
1359 	ret = modem_cmux_disconnect_async(cmux);
1360 	if (ret < 0) {
1361 		return ret;
1362 	}
1363 
1364 	if (k_event_wait(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT, false,
1365 			 MODEM_CMUX_T2_TIMEOUT) == 0) {
1366 		return -EAGAIN;
1367 	}
1368 
1369 	return 0;
1370 }
1371 
modem_cmux_disconnect_async(struct modem_cmux * cmux)1372 int modem_cmux_disconnect_async(struct modem_cmux *cmux)
1373 {
1374 	int ret = 0;
1375 
1376 	if (k_event_test(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT)) {
1377 		return -EALREADY;
1378 	}
1379 
1380 	K_SPINLOCK(&cmux->work_lock) {
1381 		if (!cmux->attached) {
1382 			ret = -EPERM;
1383 			K_SPINLOCK_BREAK;
1384 		}
1385 
1386 		if (k_work_delayable_is_pending(&cmux->disconnect_work) == false) {
1387 			k_work_schedule(&cmux->disconnect_work, K_NO_WAIT);
1388 		}
1389 	}
1390 
1391 	return ret;
1392 }
1393 
modem_cmux_release(struct modem_cmux * cmux)1394 void modem_cmux_release(struct modem_cmux *cmux)
1395 {
1396 	struct k_work_sync sync;
1397 
1398 	if (cmux->pipe == NULL) {
1399 		return;
1400 	}
1401 
1402 	K_SPINLOCK(&cmux->work_lock) {
1403 		cmux->attached = false;
1404 	}
1405 
1406 	/* Close DLCI pipes and cancel DLCI work */
1407 	modem_cmux_dlci_pipes_release(cmux);
1408 
1409 	/* Release bus pipe */
1410 	if (cmux->pipe) {
1411 		modem_pipe_release(cmux->pipe);
1412 	}
1413 
1414 	/* Cancel all work */
1415 	k_work_cancel_delayable_sync(&cmux->connect_work, &sync);
1416 	k_work_cancel_delayable_sync(&cmux->disconnect_work, &sync);
1417 	k_work_cancel_delayable_sync(&cmux->transmit_work, &sync);
1418 	k_work_cancel_delayable_sync(&cmux->receive_work, &sync);
1419 
1420 	/* Unreference pipe */
1421 	cmux->pipe = NULL;
1422 
1423 	/* Reset events */
1424 	k_event_clear(&cmux->event, MODEM_CMUX_EVENT_CONNECTED_BIT);
1425 	k_event_post(&cmux->event, MODEM_CMUX_EVENT_DISCONNECTED_BIT);
1426 }
1427