@@ -66,6 +66,8 @@ static struct br_channel {
6666 uint8_t chan_id ; /* Internal number that identifies L2CAP channel. */
6767 struct bt_l2cap_br_chan br ;
6868 bool in_use ;
69+ bool hold_credit ;
70+ struct net_buf * pending_credit [DATA_POOL_COUNT ];
6971} br_channels [CHANNELS ];
7072#endif /* CONFIG_BT_CLASSIC */
7173
@@ -305,6 +307,14 @@ static void br_disconnected_cb(struct bt_l2cap_chan *l2cap_chan)
305307 struct br_channel * chan = CONTAINER_OF (l2cap_br_chan , struct br_channel , br );
306308 struct bt_conn_info info ;
307309
310+ /* release netbuf on premature disconnection */
311+ ARRAY_FOR_EACH (chan -> pending_credit , i ) {
312+ if (chan -> pending_credit [i ] != NULL ) {
313+ net_buf_unref (chan -> pending_credit [i ]);
314+ chan -> pending_credit [i ] = NULL ;
315+ }
316+ }
317+
308318 (void )memset (& ev , 0 , sizeof (struct btp_l2cap_disconnected_ev ));
309319
310320 /* TODO: ev.result */
@@ -332,7 +342,7 @@ static void br_disconnected_cb(struct bt_l2cap_chan *l2cap_chan)
332342
333343static struct net_buf * br_alloc_buf_cb (struct bt_l2cap_chan * chan )
334344{
335- return net_buf_alloc (& data_pool , K_FOREVER );
345+ return net_buf_alloc (& data_pool , K_NO_WAIT );
336346}
337347
338348static uint8_t br_recv_cb_buf [DATA_MTU + sizeof (struct btp_l2cap_data_received_ev )];
@@ -351,6 +361,11 @@ static int br_recv_cb(struct bt_l2cap_chan *l2cap_chan, struct net_buf *buf)
351361 tester_event (BTP_SERVICE_ID_L2CAP , BTP_L2CAP_EV_DATA_RECEIVED ,
352362 br_recv_cb_buf , sizeof (* ev ) + buf -> len );
353363
364+ if (chan -> hold_credit && (net_buf_id (buf ) < (int )ARRAY_SIZE (chan -> pending_credit ))) {
365+ chan -> pending_credit [net_buf_id (buf )] = buf ;
366+ return - EINPROGRESS ;
367+ }
368+
354369 return 0 ;
355370}
356371
@@ -448,6 +463,8 @@ static uint8_t br_connect(const struct btp_l2cap_connect_v2_cmd *cp,
448463 } else {
449464 br_chan -> br .rx .fcs = BT_L2CAP_BR_FCS_16BIT ;
450465 }
466+
467+ br_chan -> hold_credit = (cp -> options & BTP_L2CAP_CONNECT_V2_OPT_HOLD_CREDIT ) != 0 ;
451468#endif /* CONFIG_BT_L2CAP_RET_FC */
452469
453470 err = bt_l2cap_chan_connect (conn , & br_chan -> br .chan , sys_le16_to_cpu (cp -> psm ));
@@ -998,6 +1015,8 @@ static int br_accept(struct bt_conn *conn, struct bt_l2cap_server *server,
9981015 } else {
9991016 chan -> br .rx .fcs = BT_L2CAP_BR_FCS_16BIT ;
10001017 }
1018+
1019+ chan -> hold_credit = (options & BTP_L2CAP_LISTEN_V2_OPT_HOLD_CREDIT ) != 0 ;
10011020#endif /* CONFIG_BT_L2CAP_RET_FC */
10021021
10031022 * l2cap_chan = & chan -> br .chan ;
@@ -1103,12 +1122,59 @@ static uint8_t listen_v2(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t
11031122 return _listen (psm , cp -> transport , response , cp -> mode , options );
11041123}
11051124
1125+ #if defined(CONFIG_BT_CLASSIC )
1126+ static uint8_t br_credits (uint8_t chan_id , void * rsp , uint16_t * rsp_len )
1127+ {
1128+ struct br_channel * chan ;
1129+
1130+ if (chan_id >= CHANNELS ) {
1131+ return BTP_STATUS_FAILED ;
1132+ }
1133+
1134+ chan = & br_channels [chan_id ];
1135+
1136+ if (!chan -> in_use ) {
1137+ return BTP_STATUS_FAILED ;
1138+ }
1139+
1140+ ARRAY_FOR_EACH (chan -> pending_credit , i ) {
1141+ if (chan -> pending_credit [i ] != NULL ) {
1142+ if (bt_l2cap_chan_recv_complete (& chan -> br .chan ,
1143+ chan -> pending_credit [i ]) < 0 ) {
1144+ return BTP_STATUS_FAILED ;
1145+ }
1146+
1147+ chan -> pending_credit [i ] = NULL ;
1148+
1149+ return BTP_STATUS_SUCCESS ;
1150+ }
1151+ }
1152+
1153+ return BTP_STATUS_SUCCESS ;
1154+ }
1155+ #else
1156+ static uint8_t br_credits (uint8_t chan_id , void * rsp , uint16_t * rsp_len )
1157+ {
1158+ return BTP_STATUS_FAILED ;
1159+ }
1160+ #endif /* CONFIG_BT_CLASSIC */
1161+
11061162static uint8_t credits (const void * cmd , uint16_t cmd_len ,
11071163 void * rsp , uint16_t * rsp_len )
11081164{
11091165 const struct btp_l2cap_credits_cmd * cp = cmd ;
11101166 struct channel * chan ;
11111167
1168+ if (IS_ENABLED (CONFIG_BT_CLASSIC )) {
1169+ uint8_t chan_id ;
1170+
1171+ chan_id = cp -> chan_id ;
1172+ if (chan_id >= ARRAY_SIZE (channels )) {
1173+ chan_id = chan_id - ARRAY_SIZE (channels );
1174+ return br_credits (chan_id , rsp , rsp_len );
1175+ }
1176+ }
1177+
11121178 if (cp -> chan_id >= CHANNELS ) {
11131179 return BTP_STATUS_FAILED ;
11141180 }
0 commit comments