@@ -648,6 +648,7 @@ static void l2cap_chan_tx_init(struct bt_l2cap_le_chan *chan)
648
648
649
649
memset (& chan -> tx , 0 , sizeof (chan -> tx ));
650
650
k_sem_init (& chan -> tx .credits , 0 , UINT_MAX );
651
+ k_fifo_init (& chan -> tx_queue );
651
652
}
652
653
653
654
static 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,
673
674
static void l2cap_chan_destroy (struct bt_l2cap_chan * chan )
674
675
{
675
676
struct bt_l2cap_le_chan * ch = BT_L2CAP_LE_CHAN (chan );
677
+ struct net_buf * buf ;
676
678
677
679
BT_DBG ("chan %p cid 0x%04x" , ch , ch -> rx .cid );
678
680
679
681
/* Cancel ongoing work */
680
682
k_delayed_work_cancel (& chan -> rtx_work );
681
683
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
+ }
686
688
687
689
/* Destroy segmented SDU if it exists */
688
690
if (ch -> _sdu ) {
@@ -1084,12 +1086,12 @@ static int l2cap_chan_le_send(struct bt_l2cap_le_chan *ch, struct net_buf *buf,
1084
1086
}
1085
1087
1086
1088
static int l2cap_chan_le_send_sdu (struct bt_l2cap_le_chan * ch ,
1087
- struct net_buf * buf )
1089
+ struct net_buf * buf , int sent )
1088
1090
{
1089
- int ret , sent , total_len ;
1091
+ int ret , total_len ;
1090
1092
struct net_buf * frag ;
1091
1093
1092
- total_len = net_buf_frags_len (buf );
1094
+ total_len = net_buf_frags_len (buf ) + sent ;
1093
1095
1094
1096
if (total_len > ch -> tx .mtu ) {
1095
1097
return - EMSGSIZE ;
@@ -1100,21 +1102,34 @@ static int l2cap_chan_le_send_sdu(struct bt_l2cap_le_chan *ch,
1100
1102
frag = frag -> frags ;
1101
1103
}
1102
1104
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
+ }
1107
1117
}
1108
1118
1109
1119
/* Send remaining segments */
1110
- for (sent = ret ; sent < total_len ; sent += ret ) {
1120
+ for (ret = 0 ; sent < total_len ; sent += ret ) {
1111
1121
/* Proceed to next fragment */
1112
1122
if (!frag -> len ) {
1113
1123
frag = net_buf_frag_del (buf , frag );
1114
1124
}
1115
1125
1116
1126
ret = l2cap_chan_le_send (ch , frag , 0 );
1117
1127
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
+ }
1118
1133
return ret ;
1119
1134
}
1120
1135
}
@@ -1126,6 +1141,40 @@ static int l2cap_chan_le_send_sdu(struct bt_l2cap_le_chan *ch,
1126
1141
return ret ;
1127
1142
}
1128
1143
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
+
1129
1178
static void le_credits (struct bt_l2cap * l2cap , uint8_t ident ,
1130
1179
struct net_buf * buf )
1131
1180
{
@@ -1163,6 +1212,8 @@ static void le_credits(struct bt_l2cap *l2cap, uint8_t ident,
1163
1212
1164
1213
BT_DBG ("chan %p total credits %u" , ch ,
1165
1214
k_sem_count_get (& ch -> tx .credits ));
1215
+
1216
+ l2cap_chan_le_send_resume (ch );
1166
1217
}
1167
1218
1168
1219
static 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)
1646
1697
return bt_l2cap_br_chan_send (chan , buf );
1647
1698
}
1648
1699
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 );
1650
1701
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
+ }
1651
1707
BT_ERR ("failed to send message %d" , err );
1652
1708
}
1653
1709
0 commit comments