Skip to content

Commit 6b374d7

Browse files
committed
modem: cmux: Handle C/R bit from address field
The C/R bit in the address field should be handled as explained in 5.2.1.2 in the spec (3GPP TS 127.010). To detect if the frame is a command or a response, we need to know who was the initiator of the CMUX channel. > Initiator is the station that take the initiative to initialize > the multiplexer (i.e. sends the SABM command at DLCI 0 ) See the table from given section of the specification. Also, on UIH frames 5.4.3.1 says > The frames sent by the initiating station have the C/R bit set to 1 > and those sent by the responding station have the C/R bit set to 0. NOTE: This is different than a C/R bit in the Type field. Signed-off-by: Seppo Takalo <[email protected]>
1 parent 169cf86 commit 6b374d7

File tree

3 files changed

+47
-9
lines changed

3 files changed

+47
-9
lines changed

include/zephyr/modem/cmux.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,11 @@ struct modem_cmux {
142142

143143
/* State */
144144
enum modem_cmux_state state;
145-
bool flow_control_on;
145+
bool flow_control_on : 1;
146+
bool initiator : 1;
146147

147148
/* Work lock */
148-
bool attached;
149+
bool attached : 1;
149150
struct k_spinlock work_lock;
150151

151152
/* Receive state*/

subsys/modem/modem_cmux.c

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -461,12 +461,13 @@ static void modem_cmux_on_cld_command(struct modem_cmux *cmux, struct modem_cmux
461461
static void modem_cmux_on_control_frame_ua(struct modem_cmux *cmux)
462462
{
463463
if (cmux->state != MODEM_CMUX_STATE_CONNECTING) {
464-
LOG_DBG("Unexpected UA frame");
464+
LOG_DBG("Unexpected UA frame in state %d", cmux->state);
465465
return;
466466
}
467467

468468
LOG_DBG("CMUX connected");
469469
cmux->state = MODEM_CMUX_STATE_CONNECTED;
470+
cmux->initiator = true;
470471
k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
471472
cmux->flow_control_on = true;
472473
k_mutex_unlock(&cmux->transmit_rb_lock);
@@ -593,16 +594,16 @@ static void modem_cmux_dm_response_transmit(struct modem_cmux *cmux)
593594

594595
static void modem_cmux_on_control_frame_sabm(struct modem_cmux *cmux)
595596
{
596-
modem_cmux_connect_response_transmit(cmux);
597-
598597
if ((cmux->state == MODEM_CMUX_STATE_CONNECTED) ||
599598
(cmux->state == MODEM_CMUX_STATE_DISCONNECTING)) {
600599
LOG_DBG("Connect request not accepted");
601600
return;
602601
}
603602

604603
LOG_DBG("CMUX connection request received");
604+
cmux->initiator = false;
605605
cmux->state = MODEM_CMUX_STATE_CONNECTED;
606+
modem_cmux_connect_response_transmit(cmux);
606607
k_mutex_lock(&cmux->transmit_rb_lock, K_FOREVER);
607608
cmux->flow_control_on = true;
608609
k_mutex_unlock(&cmux->transmit_rb_lock);
@@ -615,6 +616,11 @@ static void modem_cmux_on_control_frame(struct modem_cmux *cmux)
615616
{
616617
modem_cmux_log_received_frame(&cmux->frame);
617618

619+
if (cmux->state == MODEM_CMUX_STATE_CONNECTED && cmux->frame.cr == cmux->initiator) {
620+
LOG_DBG("Received a response frame, dropping");
621+
return;
622+
}
623+
618624
switch (cmux->frame.type) {
619625
case MODEM_CMUX_FRAME_TYPE_UA:
620626
modem_cmux_on_control_frame_ua(cmux);
@@ -659,6 +665,12 @@ static void modem_cmux_on_dlci_frame_dm(struct modem_cmux_dlci *dlci)
659665

660666
static void modem_cmux_on_dlci_frame_ua(struct modem_cmux_dlci *dlci)
661667
{
668+
/* Drop invalid UA frames */
669+
if (dlci->cmux->frame.cr != dlci->cmux->initiator) {
670+
LOG_DBG("Received a response frame, dropping");
671+
return;
672+
}
673+
662674
switch (dlci->state) {
663675
case MODEM_CMUX_DLCI_STATE_OPENING:
664676
LOG_DBG("DLCI %u opened", dlci->dlci_address);
@@ -744,6 +756,11 @@ static void modem_cmux_on_dlci_frame(struct modem_cmux *cmux)
744756

745757
modem_cmux_log_received_frame(&cmux->frame);
746758

759+
if (cmux->state != MODEM_CMUX_STATE_CONNECTED) {
760+
LOG_DBG("Unexpected DLCI frame in state %d", cmux->state);
761+
return;
762+
}
763+
747764
dlci = modem_cmux_find_dlci(cmux);
748765
if (dlci == NULL) {
749766
LOG_WRN("Frame intended for unconfigured DLCI %u.",
@@ -1085,6 +1102,7 @@ static void modem_cmux_connect_handler(struct k_work *item)
10851102
cmux = CONTAINER_OF(dwork, struct modem_cmux, connect_work);
10861103

10871104
cmux->state = MODEM_CMUX_STATE_CONNECTING;
1105+
cmux->initiator = true;
10881106

10891107
static const struct modem_cmux_frame frame = {
10901108
.dlci_address = 0,
@@ -1117,7 +1135,7 @@ static void modem_cmux_disconnect_handler(struct k_work *item)
11171135

11181136
struct modem_cmux_frame frame = {
11191137
.dlci_address = 0,
1120-
.cr = true,
1138+
.cr = cmux->initiator,
11211139
.pf = false,
11221140
.type = MODEM_CMUX_FRAME_TYPE_UIH,
11231141
.data = data,
@@ -1196,7 +1214,7 @@ static int modem_cmux_dlci_pipe_api_transmit(void *data, const uint8_t *buf, siz
11961214

11971215
struct modem_cmux_frame frame = {
11981216
.dlci_address = dlci->dlci_address,
1199-
.cr = true,
1217+
.cr = cmux->initiator,
12001218
.pf = false,
12011219
.type = MODEM_CMUX_FRAME_TYPE_UIH,
12021220
.data = buf,
@@ -1271,7 +1289,7 @@ static void modem_cmux_dlci_open_handler(struct k_work *item)
12711289

12721290
struct modem_cmux_frame frame = {
12731291
.dlci_address = dlci->dlci_address,
1274-
.cr = true,
1292+
.cr = dlci->cmux->initiator,
12751293
.pf = true,
12761294
.type = MODEM_CMUX_FRAME_TYPE_SABM,
12771295
.data = NULL,
@@ -1300,7 +1318,7 @@ static void modem_cmux_dlci_close_handler(struct k_work *item)
13001318

13011319
struct modem_cmux_frame frame = {
13021320
.dlci_address = dlci->dlci_address,
1303-
.cr = true,
1321+
.cr = dlci->cmux->initiator,
13041322
.pf = true,
13051323
.type = MODEM_CMUX_FRAME_TYPE_DISC,
13061324
.data = NULL,

tests/subsys/modem/modem_cmux/src/main.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,4 +886,23 @@ ZTEST(modem_cmux, test_modem_cmux_split_large_data)
886886
"Incorrect number of bytes transmitted %d", ret);
887887
}
888888

889+
ZTEST(modem_cmux, test_modem_cmux_invalid_cr)
890+
{
891+
uint32_t events;
892+
int ret;
893+
894+
/* We are initiator, so any CMD with CR set, should be dropped */
895+
modem_backend_mock_put(&bus_mock, cmux_frame_control_cld_cmd,
896+
sizeof(cmux_frame_control_cld_cmd));
897+
898+
modem_backend_mock_put(&bus_mock, cmux_frame_control_sabm_cmd,
899+
sizeof(cmux_frame_control_sabm_cmd));
900+
901+
902+
events = k_event_wait_all(&cmux_event, (MODEM_CMUX_EVENT_CONNECTED | MODEM_CMUX_EVENT_DISCONNECTED),
903+
false, K_MSEC(100));
904+
905+
zassert_false(events, "Wrong CMD should have been ignored");
906+
}
907+
889908
ZTEST_SUITE(modem_cmux, NULL, test_modem_cmux_setup, test_modem_cmux_before, NULL, NULL);

0 commit comments

Comments
 (0)