2626#include <zephyr/bluetooth/l2cap.h>
2727#include <zephyr/bluetooth/classic/rfcomm.h>
2828#include <zephyr/bluetooth/classic/sdp.h>
29+ #include <zephyr/bluetooth/classic/l2cap_br.h>
2930
3031#include <zephyr/shell/shell.h>
3132
@@ -646,6 +647,124 @@ static int cmd_l2cap_credits(const struct shell *sh, size_t argc, char *argv[])
646647}
647648#endif /* CONFIG_BT_L2CAP_RET_FC */
648649
650+ static void l2cap_br_echo_req (struct bt_conn * conn , uint8_t identifier , struct net_buf * buf )
651+ {
652+ bt_shell_print ("Incoming ECHO REQ data identifier %u len %u" , identifier , buf -> len );
653+
654+ if (buf -> len > 0 ) {
655+ bt_shell_hexdump (buf -> data , buf -> len );
656+ }
657+ }
658+
659+ static void l2cap_br_echo_rsp (struct bt_conn * conn , struct net_buf * buf )
660+ {
661+ bt_shell_print ("Incoming ECHO RSP data len %u" , buf -> len );
662+
663+ if (buf -> len > 0 ) {
664+ bt_shell_hexdump (buf -> data , buf -> len );
665+ }
666+ }
667+
668+ static struct bt_l2cap_br_echo_cb echo_cb = {
669+ .req = l2cap_br_echo_req ,
670+ .rsp = l2cap_br_echo_rsp ,
671+ };
672+
673+ static int cmd_l2cap_echo_reg (const struct shell * sh , size_t argc , char * argv [])
674+ {
675+ int err ;
676+
677+ err = bt_l2cap_br_echo_cb_register (& echo_cb );
678+ if (err ) {
679+ shell_error (sh , "Failed to register echo callback: %d" , - err );
680+ return err ;
681+ }
682+
683+ return 0 ;
684+ }
685+
686+ static int cmd_l2cap_echo_unreg (const struct shell * sh , size_t argc , char * argv [])
687+ {
688+ int err ;
689+
690+ err = bt_l2cap_br_echo_cb_unregister (& echo_cb );
691+ if (err ) {
692+ shell_error (sh , "Failed to unregister echo callback: %d" , - err );
693+ return err ;
694+ }
695+
696+ return 0 ;
697+ }
698+
699+ static int cmd_l2cap_echo_req (const struct shell * sh , size_t argc , char * argv [])
700+ {
701+ static uint8_t buf_data [DATA_BREDR_MTU ];
702+ int err , len = DATA_BREDR_MTU ;
703+ struct net_buf * buf ;
704+
705+ len = strtoul (argv [1 ], NULL , 10 );
706+ if (len > DATA_BREDR_MTU ) {
707+ shell_error (sh , "Length exceeds TX MTU for the channel" );
708+ return - ENOEXEC ;
709+ }
710+
711+ buf = net_buf_alloc (& data_tx_pool , K_SECONDS (2 ));
712+ if (!buf ) {
713+ shell_error (sh , "Allocation timeout, stopping TX" );
714+ return - EAGAIN ;
715+ }
716+ net_buf_reserve (buf , BT_L2CAP_BR_ECHO_REQ_RESERVE );
717+ for (int i = 0 ; i < len ; i ++ ) {
718+ buf_data [i ] = (uint8_t )i ;
719+ }
720+
721+ net_buf_add_mem (buf , buf_data , len );
722+ err = bt_l2cap_br_echo_req (default_conn , buf );
723+ if (err < 0 ) {
724+ shell_error (sh , "Unable to send ECHO REQ: %d" , - err );
725+ net_buf_unref (buf );
726+ return - ENOEXEC ;
727+ }
728+
729+ return 0 ;
730+ }
731+
732+ static int cmd_l2cap_echo_rsp (const struct shell * sh , size_t argc , char * argv [])
733+ {
734+ static uint8_t buf_data [DATA_BREDR_MTU ];
735+ int err , len = DATA_BREDR_MTU ;
736+ uint8_t identifier ;
737+ struct net_buf * buf ;
738+
739+ identifier = (uint8_t )strtoul (argv [1 ], NULL , 10 );
740+
741+ len = strtoul (argv [2 ], NULL , 10 );
742+ if (len > DATA_BREDR_MTU ) {
743+ shell_error (sh , "Length exceeds TX MTU for the channel" );
744+ return - ENOEXEC ;
745+ }
746+
747+ buf = net_buf_alloc (& data_tx_pool , K_SECONDS (2 ));
748+ if (!buf ) {
749+ shell_error (sh , "Allocation timeout, stopping TX" );
750+ return - EAGAIN ;
751+ }
752+ net_buf_reserve (buf , BT_L2CAP_BR_ECHO_RSP_RESERVE );
753+ for (int i = 0 ; i < len ; i ++ ) {
754+ buf_data [i ] = (uint8_t )i ;
755+ }
756+
757+ net_buf_add_mem (buf , buf_data , len );
758+ err = bt_l2cap_br_echo_rsp (default_conn , identifier , buf );
759+ if (err < 0 ) {
760+ shell_error (sh , "Unable to send ECHO RSP: %d" , - err );
761+ net_buf_unref (buf );
762+ return - ENOEXEC ;
763+ }
764+
765+ return 0 ;
766+ }
767+
649768static int cmd_discoverable (const struct shell * sh , size_t argc , char * argv [])
650769{
651770 int err = 0 ;
@@ -1110,6 +1229,14 @@ static int cmd_default_handler(const struct shell *sh, size_t argc, char **argv)
11101229 "<psm> <mode: none, ret, fc, eret, stream> [hold_credit] " \
11111230 "[mode_optional] [extended_control]"
11121231
1232+ SHELL_STATIC_SUBCMD_SET_CREATE (echo_cmds ,
1233+ SHELL_CMD_ARG (register , NULL , HELP_NONE , cmd_l2cap_echo_reg , 1 , 0 ),
1234+ SHELL_CMD_ARG (unregister , NULL , HELP_NONE , cmd_l2cap_echo_unreg , 1 , 0 ),
1235+ SHELL_CMD_ARG (req , NULL , "<length of data>" , cmd_l2cap_echo_req , 2 , 0 ),
1236+ SHELL_CMD_ARG (rsp , NULL , "<identifier> <length of data>" , cmd_l2cap_echo_rsp , 3 , 0 ),
1237+ SHELL_SUBCMD_SET_END
1238+ );
1239+
11131240SHELL_STATIC_SUBCMD_SET_CREATE (l2cap_cmds ,
11141241#if defined(CONFIG_BT_L2CAP_RET_FC )
11151242 SHELL_CMD_ARG (register , NULL , HELP_REG , cmd_l2cap_register , 3 , 3 ),
@@ -1124,6 +1251,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(l2cap_cmds,
11241251#if defined(CONFIG_BT_L2CAP_RET_FC )
11251252 SHELL_CMD_ARG (credits , NULL , HELP_NONE , cmd_l2cap_credits , 1 , 0 ),
11261253#endif /* CONFIG_BT_L2CAP_RET_FC */
1254+ SHELL_CMD (echo , & echo_cmds , "L2CAP BR ECHO commands" , cmd_default_handler ),
11271255 SHELL_SUBCMD_SET_END
11281256);
11291257
0 commit comments