@@ -648,6 +648,7 @@ static void l2cap_chan_tx_init(struct bt_l2cap_le_chan *chan)
648648
649649 memset (& chan -> tx , 0 , sizeof (chan -> tx ));
650650 k_sem_init (& chan -> tx .credits , 0 , UINT_MAX );
651+ k_fifo_init (& chan -> tx_queue );
651652}
652653
653654static void l2cap_chan_tx_give_credits (struct bt_l2cap_le_chan * chan ,
@@ -673,16 +674,17 @@ static void l2cap_chan_rx_give_credits(struct bt_l2cap_le_chan *chan,
673674static void l2cap_chan_destroy (struct bt_l2cap_chan * chan )
674675{
675676 struct bt_l2cap_le_chan * ch = BT_L2CAP_LE_CHAN (chan );
677+ struct net_buf * buf ;
676678
677679 BT_DBG ("chan %p cid 0x%04x" , ch , ch -> rx .cid );
678680
679681 /* Cancel ongoing work */
680682 k_delayed_work_cancel (& chan -> rtx_work );
681683
682- /* There could be a writer waiting for credits so return a dummy credit
683- * to wake it up.
684- */
685- l2cap_chan_tx_give_credits ( ch , 1 );
684+ /* Remove buffers on the TX queue */
685+ while (( buf = net_buf_get ( & ch -> tx_queue , K_NO_WAIT ))) {
686+ net_buf_unref ( buf );
687+ }
686688
687689 /* Destroy segmented SDU if it exists */
688690 if (ch -> _sdu ) {
@@ -1084,12 +1086,12 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, struct net_buf *buf,
10841086}
10851087
10861088static int l2cap_chan_le_send_sdu (struct bt_l2cap_le_chan * ch ,
1087- struct net_buf * buf )
1089+ struct net_buf * buf , int sent )
10881090{
1089- int ret , sent , total_len ;
1091+ int ret , total_len ;
10901092 struct net_buf * frag ;
10911093
1092- total_len = net_buf_frags_len (buf );
1094+ total_len = net_buf_frags_len (buf ) + sent ;
10931095
10941096 if (total_len > ch -> tx .mtu ) {
10951097 return - EMSGSIZE ;
@@ -1100,21 +1102,34 @@ static int l2cap_chan_le_send_sdu(struct bt_l2cap_le_chan *ch,
11001102 frag = frag -> frags ;
11011103 }
11021104
1103- /* Add SDU length for the first segment */
1104- ret = l2cap_chan_le_send (ch , frag , BT_L2CAP_SDU_HDR_LEN );
1105- if (ret < 0 ) {
1106- return ret ;
1105+ if (!sent ) {
1106+ /* Add SDU length for the first segment */
1107+ sent = l2cap_chan_le_send (ch , frag , BT_L2CAP_SDU_HDR_LEN );
1108+ if (sent < 0 ) {
1109+ if (sent == - EAGAIN ) {
1110+ sent = 0 ;
1111+ /* Store sent data into user_data */
1112+ memcpy (net_buf_user_data (buf ), & sent ,
1113+ sizeof (sent ));
1114+ }
1115+ return sent ;
1116+ }
11071117 }
11081118
11091119 /* Send remaining segments */
1110- for (sent = ret ; sent < total_len ; sent += ret ) {
1120+ for (ret = 0 ; sent < total_len ; sent += ret ) {
11111121 /* Proceed to next fragment */
11121122 if (!frag -> len ) {
11131123 frag = net_buf_frag_del (buf , frag );
11141124 }
11151125
11161126 ret = l2cap_chan_le_send (ch , frag , 0 );
11171127 if (ret < 0 ) {
1128+ if (ret == - EAGAIN ) {
1129+ /* Store sent data into user_data */
1130+ memcpy (net_buf_user_data (buf ), & sent ,
1131+ sizeof (sent ));
1132+ }
11181133 return ret ;
11191134 }
11201135 }
@@ -1126,6 +1141,40 @@ static int l2cap_chan_le_send_sdu(struct bt_l2cap_le_chan *ch,
11261141 return ret ;
11271142}
11281143
1144+ static struct net_buf * l2cap_chan_le_get_tx_buf (struct bt_l2cap_le_chan * ch )
1145+ {
1146+ struct net_buf * buf ;
1147+
1148+ /* Return current buffer */
1149+ if (ch -> tx_buf ) {
1150+ buf = ch -> tx_buf ;
1151+ ch -> tx_buf = NULL ;
1152+ return buf ;
1153+ }
1154+
1155+ return net_buf_get (& ch -> tx_queue , K_NO_WAIT );
1156+ }
1157+
1158+ static void l2cap_chan_le_send_resume (struct bt_l2cap_le_chan * ch )
1159+ {
1160+ struct net_buf * buf ;
1161+
1162+ /* Resume tx in case there are buffers in the queue */
1163+ while ((buf = l2cap_chan_le_get_tx_buf (ch ))) {
1164+ int sent = * ((int * )net_buf_user_data (buf ));
1165+
1166+ BT_DBG ("buf %p sent %u" , buf , sent );
1167+
1168+ sent = l2cap_chan_le_send_sdu (ch , buf , sent );
1169+ if (sent < 0 ) {
1170+ if (sent == - EAGAIN ) {
1171+ ch -> tx_buf = buf ;
1172+ }
1173+ break ;
1174+ }
1175+ }
1176+ }
1177+
11291178static void le_credits (struct bt_l2cap * l2cap , uint8_t ident ,
11301179 struct net_buf * buf )
11311180{
@@ -1163,6 +1212,8 @@ static void le_credits(struct bt_l2cap *l2cap, uint8_t ident,
11631212
11641213 BT_DBG ("chan %p total credits %u" , ch ,
11651214 k_sem_count_get (& ch -> tx .credits ));
1215+
1216+ l2cap_chan_le_send_resume (ch );
11661217}
11671218
11681219static void reject_cmd (struct bt_l2cap * l2cap , uint8_t ident ,
@@ -1646,8 +1697,13 @@ int bt_l2cap_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf)
16461697 return bt_l2cap_br_chan_send (chan , buf );
16471698 }
16481699
1649- err = l2cap_chan_le_send_sdu (BT_L2CAP_LE_CHAN (chan ), buf );
1700+ err = l2cap_chan_le_send_sdu (BT_L2CAP_LE_CHAN (chan ), buf , 0 );
16501701 if (err < 0 ) {
1702+ if (err == - EAGAIN ) {
1703+ /* Queue buffer to be sent later */
1704+ net_buf_put (& (BT_L2CAP_LE_CHAN (chan ))-> tx_queue , buf );
1705+ return * ((int * )net_buf_user_data (buf ));
1706+ }
16511707 BT_ERR ("failed to send message %d" , err );
16521708 }
16531709
0 commit comments