@@ -81,6 +81,29 @@ struct modem_cmux_command {
8181 uint8_t value [];
8282};
8383
84+ struct modem_cmux_msc_signals {
85+ uint8_t ea : 1 ; /**< Last octet, always 1 */
86+ uint8_t fc : 1 ; /**< Flow Control */
87+ uint8_t rtc : 1 ; /**< Ready to Communicate */
88+ uint8_t rtr : 1 ; /**< Ready to Transmit */
89+ uint8_t res_0 : 2 ; /**< Reserved, set to zero */
90+ uint8_t ic : 1 ; /**< Incoming call indicator */
91+ uint8_t dv : 1 ; /**< Data Valid */
92+ };
93+ struct modem_cmux_msc_addr {
94+ uint8_t ea : 1 ; /**< Last octet, always 1 */
95+ uint8_t pad_one : 1 ; /**< Set to 1 */
96+ uint8_t dlci_address : 6 ; /**< DLCI channel address */
97+ };
98+
99+ struct modem_cmux_command_msc {
100+ struct modem_cmux_command command ;
101+ uint8_t value [2 ];
102+ };
103+
104+ static struct modem_cmux_dlci * modem_cmux_find_dlci (struct modem_cmux * cmux , uint8_t dlci_address );
105+ static void modem_cmux_dlci_notify_transmit_idle (struct modem_cmux * cmux );
106+
84107static int modem_cmux_wrap_command (struct modem_cmux_command * * command , const uint8_t * data ,
85108 uint16_t data_len )
86109{
@@ -122,6 +145,53 @@ static struct modem_cmux_command *modem_cmux_command_wrap(const uint8_t *data)
122145 return (struct modem_cmux_command * )data ;
123146}
124147
148+ static struct modem_cmux_msc_signals modem_cmux_msc_signals_decode (const uint8_t byte )
149+ {
150+ struct modem_cmux_msc_signals signals ;
151+
152+ /* 3GPP TS 27.010 MSC signals octet:
153+ * |0 |1 |2 |3 |4 |5 |6 |7 |
154+ * |EA |FC|RTC|RTR|0 |0 |IC|DV|
155+ */
156+ signals .ea = (byte & BIT (0 )) ? 1 : 0 ;
157+ signals .fc = (byte & BIT (1 )) ? 1 : 0 ;
158+ signals .rtc = (byte & BIT (2 )) ? 1 : 0 ;
159+ signals .rtr = (byte & BIT (3 )) ? 1 : 0 ;
160+ signals .ic = (byte & BIT (6 )) ? 1 : 0 ;
161+ signals .dv = (byte & BIT (7 )) ? 1 : 0 ;
162+
163+ return signals ;
164+ }
165+
166+ static uint8_t modem_cmux_msc_signals_encode (const struct modem_cmux_msc_signals signals )
167+ {
168+ return (signals .ea ? BIT (0 ) : 0 ) | (signals .fc ? BIT (1 ) : 0 ) |
169+ (signals .rtc ? BIT (2 ) : 0 ) | (signals .rtr ? BIT (3 ) : 0 ) |
170+ (signals .ic ? BIT (6 ) : 0 ) | (signals .dv ? BIT (7 ) : 0 );
171+ }
172+
173+ static struct modem_cmux_msc_addr modem_cmux_msc_addr_decode (const uint8_t byte )
174+ {
175+ struct modem_cmux_msc_addr addr ;
176+
177+ /* 3GPP TS 27.010 MSC address octet:
178+ * |0 |1 |2 |3 |4 |5 |6 |7 |
179+ * |EA |1 | DLCI |
180+ */
181+ addr .ea = (byte & BIT (0 )) ? 1 : 0 ;
182+ addr .pad_one = 1 ;
183+ addr .dlci_address = (byte >> 2 ) & 0x3F ;
184+
185+ return addr ;
186+ }
187+
188+ static uint8_t modem_cmux_msc_addr_encode (const struct modem_cmux_msc_addr a )
189+ {
190+ return (a .ea ? BIT (0 ) : 0 ) | BIT (1 ) |
191+ ((a .dlci_address & 0x3F ) << 2 );
192+ }
193+
194+
125195#if CONFIG_MODEM_CMUX_LOG_FRAMES
126196static const char * modem_cmux_frame_type_to_str (enum modem_cmux_frame_types frame_type )
127197{
@@ -426,10 +496,92 @@ static void modem_cmux_acknowledge_received_frame(struct modem_cmux *cmux)
426496 }
427497}
428498
499+ static void modem_cmux_send_msc (struct modem_cmux * cmux , struct modem_cmux_dlci * dlci )
500+ {
501+ if (cmux == NULL || dlci == NULL ) {
502+ return ;
503+ }
504+
505+ struct modem_cmux_msc_addr addr = {
506+ .ea = 1 ,
507+ .pad_one = 1 ,
508+ .dlci_address = dlci -> dlci_address ,
509+ };
510+ struct modem_cmux_msc_signals signals = {
511+ .ea = 1 ,
512+ .fc = dlci -> rx_full ? 1 : 0 ,
513+ .rtc = dlci -> state == MODEM_CMUX_DLCI_STATE_OPEN ? 1 : 0 ,
514+ .rtr = dlci -> state == MODEM_CMUX_DLCI_STATE_OPEN ? 1 : 0 ,
515+ .dv = 1 ,
516+ };
517+ struct modem_cmux_command_msc cmd = {
518+ .command = {
519+ .type = {
520+ .ea = 1 ,
521+ .cr = 1 ,
522+ .value = MODEM_CMUX_COMMAND_MSC ,
523+ },
524+ .length = {
525+ .ea = 1 ,
526+ .value = sizeof (cmd .value ),
527+ },
528+ },
529+ .value [0 ] = modem_cmux_msc_addr_encode (addr ),
530+ .value [1 ] = modem_cmux_msc_signals_encode (signals ),
531+ };
532+
533+ struct modem_cmux_frame frame = {
534+ .dlci_address = 0 ,
535+ .cr = cmux -> initiator ,
536+ .pf = false,
537+ .type = MODEM_CMUX_FRAME_TYPE_UIH ,
538+ .data = (void * )& cmd ,
539+ .data_len = sizeof (cmd ),
540+ };
541+
542+ LOG_DBG ("Sending MSC command for DLCI %u, FC:%d RTR: %d DV: %d" , addr .dlci_address ,
543+ signals .fc , signals .rtr , signals .dv );
544+ modem_cmux_transmit_cmd_frame (cmux , & frame );
545+ }
546+
429547static void modem_cmux_on_msc_command (struct modem_cmux * cmux , struct modem_cmux_command * command )
430548{
431- if (command -> type .cr ) {
432- modem_cmux_acknowledge_received_frame (cmux );
549+ if (!command -> type .cr ) {
550+ return ;
551+ }
552+
553+ modem_cmux_acknowledge_received_frame (cmux );
554+
555+ uint8_t len = command -> length .value ;
556+
557+ if (len != 2 && len != 3 ) {
558+ LOG_WRN ("Unexpected MSC command length %d" , (int )len );
559+ return ;
560+ }
561+
562+ struct modem_cmux_msc_addr msc = modem_cmux_msc_addr_decode (command -> value [0 ]);
563+ struct modem_cmux_msc_signals signals = modem_cmux_msc_signals_decode (command -> value [1 ]);
564+ struct modem_cmux_dlci * dlci = modem_cmux_find_dlci (cmux , msc .dlci_address );
565+
566+ if (dlci ) {
567+ LOG_DBG ("MSC command received for DLCI %u" , msc .dlci_address );
568+ bool fc_signal = signals .fc || !signals .rtr ;
569+
570+ if (fc_signal != dlci -> flow_control ) {
571+ if (fc_signal ) {
572+ dlci -> flow_control = true;
573+ LOG_DBG ("DLCI %u flow control ON" , dlci -> dlci_address );
574+ } else {
575+ dlci -> flow_control = false;
576+ LOG_DBG ("DLCI %u flow control OFF" , dlci -> dlci_address );
577+ modem_pipe_notify_transmit_idle (& dlci -> pipe );
578+ }
579+ }
580+ /* As we have received MSC, send also our MSC */
581+ if (!dlci -> msc_sent && dlci -> state == MODEM_CMUX_DLCI_STATE_OPEN ) {
582+ dlci -> msc_sent = true;
583+ modem_cmux_send_msc (cmux , dlci );
584+ }
433585 }
434586}
435587
@@ -439,6 +591,7 @@ static void modem_cmux_on_fcon_command(struct modem_cmux *cmux)
439591 cmux -> flow_control_on = true;
440592 k_mutex_unlock (& cmux -> transmit_rb_lock );
441593 modem_cmux_acknowledge_received_frame (cmux );
594+ modem_cmux_dlci_notify_transmit_idle (cmux );
442595}
443596
444597static void modem_cmux_on_fcoff_command (struct modem_cmux * cmux )
@@ -670,15 +823,15 @@ static void modem_cmux_on_control_frame(struct modem_cmux *cmux)
670823 }
671824}
672825
673- static struct modem_cmux_dlci * modem_cmux_find_dlci (struct modem_cmux * cmux )
826+ static struct modem_cmux_dlci * modem_cmux_find_dlci (struct modem_cmux * cmux , uint8_t dlci_address )
674827{
675828 sys_snode_t * node ;
676829 struct modem_cmux_dlci * dlci ;
677830
678831 SYS_SLIST_FOR_EACH_NODE (& cmux -> dlcis , node ) {
679832 dlci = (struct modem_cmux_dlci * )node ;
680833
681- if (dlci -> dlci_address == cmux -> frame . dlci_address ) {
834+ if (dlci -> dlci_address == dlci_address ) {
682835 return dlci ;
683836 }
684837 }
@@ -710,6 +863,12 @@ static void modem_cmux_on_dlci_frame_ua(struct modem_cmux_dlci *dlci)
710863 k_mutex_lock (& dlci -> receive_rb_lock , K_FOREVER );
711864 ring_buf_reset (& dlci -> receive_rb );
712865 k_mutex_unlock (& dlci -> receive_rb_lock );
866+ if (dlci -> cmux -> initiator ) {
867+ modem_cmux_send_msc (dlci -> cmux , dlci );
868+ dlci -> msc_sent = true;
869+ } else {
870+ dlci -> msc_sent = false;
871+ }
713872 break ;
714873
715874 case MODEM_CMUX_DLCI_STATE_CLOSING :
@@ -742,6 +901,12 @@ static void modem_cmux_on_dlci_frame_uih(struct modem_cmux_dlci *dlci)
742901 LOG_WRN ("DLCI %u receive buffer overrun (dropped %u out of %u bytes)" ,
743902 dlci -> dlci_address , cmux -> frame .data_len - written , cmux -> frame .data_len );
744903 }
904+ if (written < cmux -> frame .data_len ||
905+ ring_buf_space_get (& dlci -> receive_rb ) < MODEM_CMUX_DATA_FRAME_SIZE_MAX ) {
906+ LOG_WRN ("DLCI %u receive buffer is full" , dlci -> dlci_address );
907+ dlci -> rx_full = true;
908+ modem_cmux_send_msc (cmux , dlci );
909+ }
745910 modem_pipe_notify_receive_ready (& dlci -> pipe );
746911}
747912
@@ -758,6 +923,7 @@ static void modem_cmux_on_dlci_frame_sabm(struct modem_cmux_dlci *dlci)
758923
759924 LOG_DBG ("DLCI %u SABM request accepted, DLCI opened" , dlci -> dlci_address );
760925 dlci -> state = MODEM_CMUX_DLCI_STATE_OPEN ;
926+ dlci -> msc_sent = false;
761927 modem_pipe_notify_opened (& dlci -> pipe );
762928 k_mutex_lock (& dlci -> receive_rb_lock , K_FOREVER );
763929 ring_buf_reset (& dlci -> receive_rb );
@@ -791,7 +957,7 @@ static void modem_cmux_on_dlci_frame(struct modem_cmux *cmux)
791957 return ;
792958 }
793959
794- dlci = modem_cmux_find_dlci (cmux );
960+ dlci = modem_cmux_find_dlci (cmux , cmux -> frame . dlci_address );
795961 if (dlci == NULL ) {
796962 LOG_WRN ("Frame intended for unconfigured DLCI %u." ,
797963 cmux -> frame .dlci_address );
@@ -1066,7 +1232,9 @@ static void modem_cmux_dlci_notify_transmit_idle(struct modem_cmux *cmux)
10661232
10671233 SYS_SLIST_FOR_EACH_NODE (& cmux -> dlcis , node ) {
10681234 dlci = (struct modem_cmux_dlci * )node ;
1069- modem_pipe_notify_transmit_idle (& dlci -> pipe );
1235+ if (!dlci -> flow_control ) {
1236+ modem_pipe_notify_transmit_idle (& dlci -> pipe );
1237+ }
10701238 }
10711239}
10721240
@@ -1241,6 +1409,10 @@ static int modem_cmux_dlci_pipe_api_transmit(void *data, const uint8_t *buf, siz
12411409 struct modem_cmux * cmux = dlci -> cmux ;
12421410 int ret = 0 ;
12431411
1412+ if (dlci -> flow_control ) {
1413+ return 0 ;
1414+ }
1415+
12441416 K_SPINLOCK (& cmux -> work_lock ) {
12451417 if (!cmux -> attached ) {
12461418 ret = - EPERM ;
@@ -1275,6 +1447,15 @@ static int modem_cmux_dlci_pipe_api_receive(void *data, uint8_t *buf, size_t siz
12751447
12761448 ret = ring_buf_get (& dlci -> receive_rb , buf , size );
12771449 k_mutex_unlock (& dlci -> receive_rb_lock );
1450+
1451+ /* Release FC if set */
1452+ if (dlci -> rx_full &&
1453+ ring_buf_space_get (& dlci -> receive_rb ) >= MODEM_CMUX_DATA_FRAME_SIZE_MAX ) {
1454+ LOG_DBG ("DLCI %u receive buffer is no longer full" , dlci -> dlci_address );
1455+ dlci -> rx_full = false;
1456+ modem_cmux_send_msc (dlci -> cmux , dlci );
1457+ }
1458+
12781459 return ret ;
12791460}
12801461
@@ -1321,6 +1502,7 @@ static void modem_cmux_dlci_open_handler(struct k_work *item)
13211502 dlci = CONTAINER_OF (dwork , struct modem_cmux_dlci , open_work );
13221503
13231504 dlci -> state = MODEM_CMUX_DLCI_STATE_OPENING ;
1505+ dlci -> msc_sent = false;
13241506
13251507 struct modem_cmux_frame frame = {
13261508 .dlci_address = dlci -> dlci_address ,
0 commit comments