@@ -80,7 +80,7 @@ struct modem_cmux_command_length {
8080struct 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
8686struct 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-
106101static struct modem_cmux_dlci * modem_cmux_find_dlci (struct modem_cmux * cmux , uint8_t dlci_address );
107102static 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
150210static 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
478539static 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)
655722static 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
690760static 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