@@ -34,6 +34,7 @@ static struct channel {
3434 uint8_t chan_id ; /* Internal number that identifies L2CAP channel. */
3535 struct bt_l2cap_le_chan le ;
3636 bool in_use ;
37+ struct net_buf * pending_credit ;
3738} channels [CHANNELS ];
3839
3940/* TODO Extend to support multiple servers */
@@ -58,6 +59,14 @@ static int recv_cb(struct bt_l2cap_chan *l2cap_chan, struct net_buf *buf)
5859 tester_send (BTP_SERVICE_ID_L2CAP , L2CAP_EV_DATA_RECEIVED ,
5960 CONTROLLER_INDEX , recv_cb_buf , sizeof (* ev ) + buf -> len );
6061
62+ if (!chan -> pending_credit ) {
63+ /* no need for extra ref, as when returning EINPROGRESS user
64+ * becomes owner of the netbuf
65+ */
66+ chan -> pending_credit = buf ;
67+ return - EINPROGRESS ;
68+ }
69+
6170 return 0 ;
6271}
6372
@@ -97,6 +106,12 @@ static void disconnected_cb(struct bt_l2cap_chan *l2cap_chan)
97106 struct channel * chan = CONTAINER_OF (l2cap_chan , struct channel , le );
98107 struct bt_conn_info info ;
99108
109+ /* release netbuf on premature disconnection */
110+ if (chan -> pending_credit ) {
111+ net_buf_unref (chan -> pending_credit );
112+ chan -> pending_credit = NULL ;
113+ }
114+
100115 (void )memset (& ev , 0 , sizeof (struct l2cap_disconnected_ev ));
101116
102117 /* TODO: ev.result */
@@ -138,6 +153,8 @@ static struct channel *get_free_channel()
138153 }
139154
140155 chan = & channels [i ];
156+
157+ (void )memset (chan , 0 , sizeof (* chan ));
141158 chan -> chan_id = i ;
142159
143160 channels [i ].in_use = true;
@@ -404,6 +421,33 @@ static void listen(uint8_t *data, uint16_t len)
404421 BTP_STATUS_FAILED );
405422}
406423
424+ static void credits (uint8_t * data , uint16_t len )
425+ {
426+ const struct l2cap_credits_cmd * cmd = (void * )data ;
427+ struct channel * chan = & channels [cmd -> chan_id ];
428+
429+ if (!chan -> in_use ) {
430+ goto fail ;
431+ }
432+
433+ if (chan -> pending_credit ) {
434+ if (bt_l2cap_chan_recv_complete (& chan -> le .chan ,
435+ chan -> pending_credit ) < 0 ) {
436+ goto fail ;
437+ }
438+
439+ chan -> pending_credit = NULL ;
440+ }
441+
442+ tester_rsp (BTP_SERVICE_ID_L2CAP , L2CAP_CREDITS , CONTROLLER_INDEX ,
443+ BTP_STATUS_SUCCESS );
444+ return ;
445+
446+ fail :
447+ tester_rsp (BTP_SERVICE_ID_L2CAP , L2CAP_CREDITS , CONTROLLER_INDEX ,
448+ BTP_STATUS_FAILED );
449+ }
450+
407451static void supported_commands (uint8_t * data , uint16_t len )
408452{
409453 uint8_t cmds [2 ];
@@ -416,6 +460,7 @@ static void supported_commands(uint8_t *data, uint16_t len)
416460 tester_set_bit (cmds , L2CAP_DISCONNECT );
417461 tester_set_bit (cmds , L2CAP_LISTEN );
418462 tester_set_bit (cmds , L2CAP_SEND_DATA );
463+ tester_set_bit (cmds , L2CAP_CREDITS );
419464#if defined(CONFIG_BT_EATT )
420465 tester_set_bit (cmds , L2CAP_DISCONNECT_EATT_CHANS );
421466#endif
@@ -442,6 +487,9 @@ void tester_handle_l2cap(uint8_t opcode, uint8_t index, uint8_t *data,
442487 case L2CAP_LISTEN :
443488 listen (data , len );
444489 return ;
490+ case L2CAP_CREDITS :
491+ credits (data , len );
492+ return ;
445493#if defined(CONFIG_BT_EATT )
446494 case L2CAP_DISCONNECT_EATT_CHANS :
447495 disconnect_eatt_chans (data , len );
0 commit comments