Skip to content

Commit 67728fa

Browse files
committed
modem: cmux: Define encoding and decoding functions for commands
Instead of relying non-standard compiler behavior, define encode and decode functions for all CMUX command structures. Final command is encoded into a shared buffer, because it is always copied directly to TX ringbuffer. Signed-off-by: Seppo Takalo <[email protected]>
1 parent 76b510c commit 67728fa

File tree

1 file changed

+162
-84
lines changed

1 file changed

+162
-84
lines changed

subsys/modem/modem_cmux.c

Lines changed: 162 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ struct modem_cmux_command_length {
8080
struct modem_cmux_command {
8181
struct modem_cmux_command_type type;
8282
struct modem_cmux_command_length length;
83-
uint8_t value[];
83+
uint8_t value[MODEM_CMUX_CMD_DATA_SIZE_MAX - 2]; /* Subtract type and length bytes */
8484
};
8585

8686
struct modem_cmux_msc_signals {
@@ -98,53 +98,113 @@ struct modem_cmux_msc_addr {
9898
uint8_t dlci_address: 6; /**< DLCI channel address */
9999
};
100100

101-
struct modem_cmux_command_msc {
102-
struct modem_cmux_command command;
103-
uint8_t value[2];
104-
};
105-
106101
static struct modem_cmux_dlci *modem_cmux_find_dlci(struct modem_cmux *cmux, uint8_t dlci_address);
107102
static void modem_cmux_dlci_notify_transmit_idle(struct modem_cmux *cmux);
108103

109-
static int modem_cmux_wrap_command(struct modem_cmux_command **command, const uint8_t *data,
110-
uint16_t data_len)
104+
static void set_state(struct modem_cmux *cmux, enum modem_cmux_state state)
111105
{
112-
if ((data == NULL) || (data_len < 2)) {
113-
return -EINVAL;
114-
}
106+
cmux->state = state;
107+
k_event_set(&cmux->event, BIT(state));
108+
}
115109

116-
(*command) = (struct modem_cmux_command *)data;
110+
static bool wait_state(struct modem_cmux *cmux, enum modem_cmux_state state, k_timeout_t timeout)
111+
{
112+
return k_event_wait(&cmux->event, BIT(state), false, timeout) == BIT(state);
113+
}
117114

118-
if (((*command)->length.ea == 0) || ((*command)->type.ea == 0)) {
119-
return -EINVAL;
120-
}
115+
static bool is_connected(struct modem_cmux *cmux)
116+
{
117+
return cmux->state == MODEM_CMUX_STATE_CONNECTED;
118+
}
121119

122-
if ((*command)->length.value != (data_len - 2)) {
123-
return -EINVAL;
120+
static struct modem_cmux_command_type modem_cmux_command_type_decode(const uint8_t byte)
121+
{
122+
struct modem_cmux_command_type type = {
123+
.ea = (byte & MODEM_CMUX_EA) ? 1 : 0,
124+
.cr = (byte & MODEM_CMUX_CR) ? 1 : 0,
125+
.value = (byte >> 2) & 0x3F,
126+
};
127+
128+
if (type.ea == 0) {
129+
return (struct modem_cmux_command_type){0};
124130
}
125131

126-
return 0;
132+
return type;
127133
}
128134

129-
static void set_state(struct modem_cmux *cmux, enum modem_cmux_state state)
135+
static uint8_t modem_cmux_command_type_encode(const struct modem_cmux_command_type type)
130136
{
131-
cmux->state = state;
132-
k_event_set(&cmux->event, BIT(state));
137+
return (type.ea ? MODEM_CMUX_EA : 0) |
138+
(type.cr ? MODEM_CMUX_CR : 0) |
139+
((type.value & 0x3F) << 2);
133140
}
134141

135-
static bool wait_state(struct modem_cmux *cmux, enum modem_cmux_state state, k_timeout_t timeout)
142+
static struct modem_cmux_command_length modem_cmux_command_length_decode(const uint8_t byte)
136143
{
137-
return k_event_wait(&cmux->event, BIT(state), false, timeout) == BIT(state);
144+
struct modem_cmux_command_length length = {
145+
.ea = (byte & MODEM_CMUX_EA) ? 1 : 0,
146+
.value = (byte >> 1) & 0x7F,
147+
};
148+
149+
if (length.ea == 0) {
150+
return (struct modem_cmux_command_length){0};
151+
}
152+
153+
return length;
138154
}
139155

140-
static bool is_connected(struct modem_cmux *cmux)
156+
static uint8_t modem_cmux_command_length_encode(const struct modem_cmux_command_length length)
141157
{
142-
return cmux->state == MODEM_CMUX_STATE_CONNECTED;
158+
return (length.ea ? MODEM_CMUX_EA : 0) |
159+
((length.value & 0x7F) << 1);
143160
}
144161

145-
static struct modem_cmux_command *modem_cmux_command_wrap(const uint8_t *data)
162+
static struct modem_cmux_command modem_cmux_command_decode(const uint8_t *data, size_t len)
146163
{
147-
return (struct modem_cmux_command *)data;
164+
if (len < 2) {
165+
return (struct modem_cmux_command){0};
166+
}
167+
168+
struct modem_cmux_command command = {
169+
.type = modem_cmux_command_type_decode(data[0]),
170+
.length = modem_cmux_command_length_decode(data[1]),
171+
};
172+
173+
if (command.type.ea == 0 || command.length.ea == 0 ||
174+
command.length.value > MODEM_CMUX_CMD_DATA_SIZE_MAX ||
175+
(2 + command.length.value) > len) {
176+
return (struct modem_cmux_command){0};
177+
}
178+
179+
memcpy(&command.value[0], &data[2], command.length.value);
180+
181+
return command;
182+
}
183+
184+
/**
185+
* @brief Encode command into a shared buffer
186+
*
187+
* Not a thread safe, so can only be used within a workqueue context and data
188+
* must be copied out to a TX ringbuffer.
189+
*
190+
* @param command command to encode
191+
* @param len encoded length of the command is written here
192+
* @return pointer to encoded command buffer on success, NULL on failure
193+
*/
194+
static uint8_t *modem_cmux_command_encode(struct modem_cmux_command *command, uint16_t *len)
195+
{
196+
static uint8_t buf[MODEM_CMUX_CMD_DATA_SIZE_MAX];
197+
if (len == NULL || (2 + command->length.value) > MODEM_CMUX_CMD_DATA_SIZE_MAX) {
198+
LOG_ERR("command encode failed");
199+
return NULL;
200+
}
201+
buf[0] = modem_cmux_command_type_encode(command->type);
202+
buf[1] = modem_cmux_command_length_encode(command->length);
203+
if (command->length.value > 0) {
204+
memcpy(&buf[2], &command->value[0], command->length.value);
205+
}
206+
*len = 2 + command->length.value;
207+
return buf;
148208
}
149209

150210
static struct modem_cmux_msc_signals modem_cmux_msc_signals_decode(const uint8_t byte)
@@ -421,7 +481,7 @@ static bool modem_cmux_transmit_cmd_frame(struct modem_cmux *cmux,
421481
const struct modem_cmux_frame *frame)
422482
{
423483
uint16_t space;
424-
struct modem_cmux_command *command;
484+
struct modem_cmux_command command;
425485

426486
k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
427487
space = ring_buf_space_get(&cmux->transmit_rb);
@@ -433,8 +493,9 @@ static bool modem_cmux_transmit_cmd_frame(struct modem_cmux *cmux,
433493
}
434494

435495
modem_cmux_log_transmit_frame(frame);
436-
if (modem_cmux_wrap_command(&command, frame->data, frame->data_len) == 0) {
437-
modem_cmux_log_transmit_command(command);
496+
command = modem_cmux_command_decode(frame->data, frame->data_len);
497+
if (command.type.value != 0) {
498+
modem_cmux_log_transmit_command(&command);
438499
}
439500

440501
modem_cmux_transmit_frame(cmux, frame);
@@ -477,7 +538,7 @@ static int16_t modem_cmux_transmit_data_frame(struct modem_cmux *cmux,
477538

478539
static void modem_cmux_acknowledge_received_frame(struct modem_cmux *cmux)
479540
{
480-
struct modem_cmux_command *command;
541+
struct modem_cmux_command_type command;
481542
struct modem_cmux_frame frame;
482543
uint8_t data[MODEM_CMUX_CMD_DATA_SIZE_MAX];
483544

@@ -488,8 +549,9 @@ static void modem_cmux_acknowledge_received_frame(struct modem_cmux *cmux)
488549

489550
memcpy(&frame, &cmux->frame, sizeof(cmux->frame));
490551
memcpy(data, cmux->frame.data, cmux->frame.data_len);
491-
modem_cmux_wrap_command(&command, data, cmux->frame.data_len);
492-
command->type.cr = 0;
552+
command = modem_cmux_command_type_decode(data[0]);
553+
command.cr = 0;
554+
data[0] = modem_cmux_command_type_encode(command);
493555
frame.data = data;
494556
frame.data_len = cmux->frame.data_len;
495557

@@ -516,29 +578,34 @@ static void modem_cmux_send_msc(struct modem_cmux *cmux, struct modem_cmux_dlci
516578
.rtr = dlci->state == MODEM_CMUX_DLCI_STATE_OPEN ? 1 : 0,
517579
.dv = 1,
518580
};
519-
struct modem_cmux_command_msc cmd = {
520-
.command = {
521-
.type = {
522-
.ea = 1,
523-
.cr = 1,
524-
.value = MODEM_CMUX_COMMAND_MSC,
525-
},
526-
.length = {
527-
.ea = 1,
528-
.value = sizeof(cmd.value),
529-
},
581+
struct modem_cmux_command cmd = {
582+
.type = {
583+
.ea = 1,
584+
.cr = 1,
585+
.value = MODEM_CMUX_COMMAND_MSC,
586+
},
587+
.length = {
588+
.ea = 1,
589+
.value = 2,
530590
},
531591
.value[0] = modem_cmux_msc_addr_encode(addr),
532592
.value[1] = modem_cmux_msc_signals_encode(signals),
533593
};
534594

595+
uint16_t len;
596+
uint8_t *data = modem_cmux_command_encode(&cmd, &len);
597+
598+
if (data == NULL) {
599+
return;
600+
}
601+
535602
struct modem_cmux_frame frame = {
536603
.dlci_address = 0,
537604
.cr = cmux->initiator,
538605
.pf = false,
539606
.type = MODEM_CMUX_FRAME_TYPE_UIH,
540-
.data = (void *)&cmd,
541-
.data_len = sizeof(cmd),
607+
.data = data,
608+
.data_len = len,
542609
};
543610

544611
LOG_DBG("Sending MSC command for DLCI %u, FC:%d RTR: %d DV: %d", addr.dlci_address,
@@ -655,60 +722,64 @@ static void modem_cmux_on_control_frame_ua(struct modem_cmux *cmux)
655722
static void modem_cmux_respond_unsupported_cmd(struct modem_cmux *cmux)
656723
{
657724
struct modem_cmux_frame frame = cmux->frame;
658-
struct modem_cmux_command *cmd;
725+
struct modem_cmux_command cmd = modem_cmux_command_decode(frame.data, frame.data_len);
659726

660-
if (modem_cmux_wrap_command(&cmd, frame.data, frame.data_len) < 0) {
727+
if (cmd.type.value == 0) {
661728
LOG_WRN("Invalid command");
662729
return;
663730
}
664731

665-
struct {
666-
/* 3GPP TS 27.010: 5.4.6.3.8 Non Supported Command Response (NSC) */
667-
struct modem_cmux_command nsc;
668-
struct modem_cmux_command_type value;
669-
} nsc_cmd = {
670-
.nsc = {
671-
.type = {
672-
.ea = 1,
673-
.cr = 0,
674-
.value = MODEM_CMUX_COMMAND_NSC,
675-
},
676-
.length = {
677-
.ea = 1,
678-
.value = 1,
679-
},
732+
733+
/* 3GPP TS 27.010: 5.4.6.3.8 Non Supported Command Response (NSC) */
734+
struct modem_cmux_command nsc_cmd = {
735+
.type = {
736+
.ea = 1,
737+
.cr = 0,
738+
.value = MODEM_CMUX_COMMAND_NSC,
680739
},
681-
.value = cmd->type,
740+
.length = {
741+
.ea = 1,
742+
.value = 1,
743+
},
744+
.value[0] = modem_cmux_command_type_encode(cmd.type),
682745
};
683746

684-
frame.data = (uint8_t *)&nsc_cmd;
685-
frame.data_len = sizeof(nsc_cmd);
747+
uint16_t len;
748+
uint8_t *data = modem_cmux_command_encode(&nsc_cmd, &len);
749+
750+
if (data == NULL) {
751+
return;
752+
}
753+
754+
frame.data = data;
755+
frame.data_len = len;
686756

687757
modem_cmux_transmit_cmd_frame(cmux, &frame);
688758
}
689759

690760
static void modem_cmux_on_control_frame_uih(struct modem_cmux *cmux)
691761
{
692-
struct modem_cmux_command *command;
762+
struct modem_cmux_command command;
693763

694764
if ((cmux->state != MODEM_CMUX_STATE_CONNECTED) &&
695765
(cmux->state != MODEM_CMUX_STATE_DISCONNECTING)) {
696766
LOG_DBG("Unexpected UIH frame");
697767
return;
698768
}
699769

700-
if (modem_cmux_wrap_command(&command, cmux->frame.data, cmux->frame.data_len) < 0) {
770+
command = modem_cmux_command_decode(cmux->frame.data, cmux->frame.data_len);
771+
if (command.type.value == 0) {
701772
LOG_WRN("Invalid command");
702773
return;
703774
}
704775

705-
modem_cmux_log_received_command(command);
776+
modem_cmux_log_received_command(&command);
706777

707-
if (!command->type.cr) {
778+
if (!command.type.cr) {
708779
LOG_DBG("Received response command");
709-
switch (command->type.value) {
780+
switch (command.type.value) {
710781
case MODEM_CMUX_COMMAND_CLD:
711-
modem_cmux_on_cld_command(cmux, command);
782+
modem_cmux_on_cld_command(cmux, &command);
712783
break;
713784
default:
714785
/* Responses to other commands are ignored */
@@ -717,13 +788,13 @@ static void modem_cmux_on_control_frame_uih(struct modem_cmux *cmux)
717788
return;
718789
}
719790

720-
switch (command->type.value) {
791+
switch (command.type.value) {
721792
case MODEM_CMUX_COMMAND_CLD:
722-
modem_cmux_on_cld_command(cmux, command);
793+
modem_cmux_on_cld_command(cmux, &command);
723794
break;
724795

725796
case MODEM_CMUX_COMMAND_MSC:
726-
modem_cmux_on_msc_command(cmux, command);
797+
modem_cmux_on_msc_command(cmux, &command);
727798
break;
728799

729800
case MODEM_CMUX_COMMAND_FCON:
@@ -1321,8 +1392,6 @@ static void modem_cmux_disconnect_handler(struct k_work *item)
13211392
{
13221393
struct k_work_delayable *dwork = k_work_delayable_from_work(item);
13231394
struct modem_cmux *cmux = CONTAINER_OF(dwork, struct modem_cmux, disconnect_work);
1324-
struct modem_cmux_command *command;
1325-
uint8_t data[2];
13261395

13271396
if (cmux->state == MODEM_CMUX_STATE_DISCONNECTING) {
13281397
disconnect(cmux);
@@ -1331,20 +1400,29 @@ static void modem_cmux_disconnect_handler(struct k_work *item)
13311400
k_work_schedule(&cmux->disconnect_work, MODEM_CMUX_T1_TIMEOUT);
13321401
}
13331402

1334-
command = modem_cmux_command_wrap(data);
1335-
command->type.ea = 1;
1336-
command->type.cr = 1;
1337-
command->type.value = MODEM_CMUX_COMMAND_CLD;
1338-
command->length.ea = 1;
1339-
command->length.value = 0;
1403+
struct modem_cmux_command command = {
1404+
.type.ea = 1,
1405+
.type.cr = 1,
1406+
.type.value = MODEM_CMUX_COMMAND_CLD,
1407+
.length.ea = 1,
1408+
.length.value = 0,
1409+
};
1410+
1411+
uint16_t len;
1412+
uint8_t *data = modem_cmux_command_encode(&command, &len);
1413+
1414+
if (data == NULL) {
1415+
return;
1416+
}
1417+
13401418

13411419
struct modem_cmux_frame frame = {
13421420
.dlci_address = 0,
13431421
.cr = cmux->initiator,
13441422
.pf = false,
13451423
.type = MODEM_CMUX_FRAME_TYPE_UIH,
13461424
.data = data,
1347-
.data_len = sizeof(data),
1425+
.data_len = len,
13481426
};
13491427

13501428
/* Transmit close down command */

0 commit comments

Comments
 (0)