@@ -66,6 +66,11 @@ static struct br_channel {
6666
6767/* TODO Extend to support multiple servers */
6868static struct bt_l2cap_server servers [SERVERS ];
69+ struct server_settings {
70+ uint8_t mode ;
71+ uint32_t options ;
72+ };
73+ static struct server_settings server_settings [SERVERS ];
6974
7075#if defined(CONFIG_BT_L2CAP_SEG_RECV )
7176static void seg_recv_cb (struct bt_l2cap_chan * l2cap_chan , size_t sdu_len , off_t seg_offset ,
@@ -862,6 +867,15 @@ static struct bt_l2cap_server *get_free_server(void)
862867 return NULL ;
863868}
864869
870+ static uint8_t get_server_index (struct bt_l2cap_server * server )
871+ {
872+ ptrdiff_t index = 0 ;
873+
874+ index = server - servers ;
875+
876+ return (uint8_t )index ;
877+ }
878+
865879static bool is_free_psm (uint16_t psm )
866880{
867881 uint8_t i ;
@@ -911,6 +925,9 @@ static int br_accept(struct bt_conn *conn, struct bt_l2cap_server *server,
911925 struct bt_l2cap_chan * * l2cap_chan )
912926{
913927 struct br_channel * chan ;
928+ __maybe_unused uint16_t options = 0 ;
929+ __maybe_unused uint8_t mode = BTP_L2CAP_LISTEN_V2_MODE_NONE ;
930+ __maybe_unused uint8_t index ;
914931
915932 if (bt_conn_enc_key_size (conn ) < req_keysize ) {
916933 return - EPERM ;
@@ -928,6 +945,56 @@ static int br_accept(struct bt_conn *conn, struct bt_l2cap_server *server,
928945 chan -> br .chan .ops = & br_l2cap_ops ;
929946 chan -> br .rx .mtu = DATA_MTU_INITIAL ;
930947
948+ #if defined(CONFIG_BT_L2CAP_RET_FC )
949+ index = get_server_index (server );
950+ if (index < ARRAY_SIZE (server_settings )) {
951+ options = server_settings [index ].options ;
952+ mode = server_settings [index ].mode ;
953+ }
954+
955+ switch (mode ) {
956+ case BTP_L2CAP_LISTEN_V2_MODE_RET :
957+ chan -> br .rx .mode = BT_L2CAP_BR_LINK_MODE_RET ;
958+ chan -> br .rx .max_transmit = 3 ;
959+ break ;
960+ case BTP_L2CAP_LISTEN_V2_MODE_FC :
961+ chan -> br .rx .mode = BT_L2CAP_BR_LINK_MODE_FC ;
962+ chan -> br .rx .max_transmit = 3 ;
963+ break ;
964+ case BTP_L2CAP_LISTEN_V2_MODE_ERET :
965+ chan -> br .rx .mode = BT_L2CAP_BR_LINK_MODE_ERET ;
966+ chan -> br .rx .max_transmit = 3 ;
967+ break ;
968+ case BTP_L2CAP_LISTEN_V2_MODE_STREAM :
969+ chan -> br .rx .mode = BT_L2CAP_BR_LINK_MODE_STREAM ;
970+ chan -> br .rx .max_transmit = 0 ;
971+ break ;
972+ default :
973+ chan -> br .rx .mode = BT_L2CAP_BR_LINK_MODE_BASIC ;
974+ chan -> br .rx .max_transmit = 0 ;
975+ break ;
976+ }
977+
978+ if (options & BTP_L2CAP_LISTEN_V2_OPT_EXT_WIN_SIZE ) {
979+ chan -> br .rx .extended_control = true;
980+ } else {
981+ chan -> br .rx .extended_control = false;
982+ }
983+
984+ if (options & BTP_L2CAP_LISTEN_V2_OPT_MODE_OPTIONAL ) {
985+ chan -> br .rx .optional = true;
986+ } else {
987+ chan -> br .rx .optional = false;
988+ }
989+
990+ chan -> br .rx .max_window = CONFIG_BT_L2CAP_MAX_WINDOW_SIZE ;
991+ if (options & BTP_L2CAP_LISTEN_V2_OPT_NO_FCS ) {
992+ chan -> br .rx .fcs = BT_L2CAP_BR_FCS_NO ;
993+ } else {
994+ chan -> br .rx .fcs = BT_L2CAP_BR_FCS_16BIT ;
995+ }
996+ #endif /* CONFIG_BT_L2CAP_RET_FC */
997+
931998 * l2cap_chan = & chan -> br .chan ;
932999
9331000 return 0 ;
@@ -940,25 +1007,29 @@ static int br_accept(struct bt_conn *conn, struct bt_l2cap_server *server,
9401007}
9411008#endif /* CONFIG_BT_CLASSIC */
9421009
943- static uint8_t listen ( const void * cmd , uint16_t cmd_len ,
944- void * rsp , uint16_t * rsp_len )
1010+ static uint8_t _listen ( uint16_t psm , uint8_t transport , uint16_t response , uint8_t mode ,
1011+ uint32_t options )
9451012{
946- const struct btp_l2cap_listen_cmd * cp = cmd ;
9471013 struct bt_l2cap_server * server ;
948- uint16_t psm = sys_le16_to_cpu (cp -> psm );
9491014
9501015 if (psm == 0 || !is_free_psm (psm )) {
9511016 return BTP_STATUS_FAILED ;
9521017 }
9531018
1019+ if (mode > BTP_L2CAP_LISTEN_V2_MODE_VALID ) {
1020+ return BTP_STATUS_FAILED ;
1021+ }
1022+
9541023 server = get_free_server ();
9551024 if (!server ) {
9561025 return BTP_STATUS_FAILED ;
9571026 }
9581027
9591028 server -> psm = psm ;
1029+ server_settings [get_server_index (server )].mode = mode ;
1030+ server_settings [get_server_index (server )].options = options ;
9601031
961- switch (cp -> response ) {
1032+ switch (response ) {
9621033 case BTP_L2CAP_CONNECTION_RESPONSE_SUCCESS :
9631034 break ;
9641035 case BTP_L2CAP_CONNECTION_RESPONSE_INSUFF_ENC_KEY :
@@ -978,26 +1049,53 @@ static uint8_t listen(const void *cmd, uint16_t cmd_len,
9781049 server -> sec_level = BT_SECURITY_L4 ;
9791050 break ;
9801051 default :
981- return BTP_STATUS_FAILED ;
1052+ goto failed ;
9821053 }
9831054
984- if (cp -> transport == BTP_L2CAP_TRANSPORT_LE ) {
1055+ if (transport == BTP_L2CAP_TRANSPORT_LE ) {
1056+ if (mode != BTP_L2CAP_LISTEN_V2_MODE_NONE ) {
1057+ goto failed ;
1058+ }
1059+
9851060 server -> accept = accept ;
9861061 if (bt_l2cap_server_register (server ) < 0 ) {
987- server -> psm = 0U ;
988- return BTP_STATUS_FAILED ;
1062+ goto failed ;
9891063 }
990- } else if (IS_ENABLED (CONFIG_BT_CLASSIC ) && (cp -> transport == BTP_L2CAP_TRANSPORT_BREDR )) {
1064+ } else if (IS_ENABLED (CONFIG_BT_CLASSIC ) && (transport == BTP_L2CAP_TRANSPORT_BREDR )) {
9911065 server -> accept = br_accept ;
9921066 if (bt_l2cap_br_server_register (server ) < 0 ) {
993- server -> psm = 0U ;
994- return BTP_STATUS_FAILED ;
1067+ goto failed ;
9951068 }
9961069 } else {
997- return BTP_STATUS_FAILED ;
1070+ goto failed ;
9981071 }
9991072
10001073 return BTP_STATUS_SUCCESS ;
1074+
1075+ failed :
1076+ server_settings [get_server_index (server )].mode = 0 ;
1077+ server_settings [get_server_index (server )].options = 0 ;
1078+ server -> psm = 0U ;
1079+ return BTP_STATUS_FAILED ;
1080+ }
1081+
1082+ static uint8_t listen (const void * cmd , uint16_t cmd_len , void * rsp , uint16_t * rsp_len )
1083+ {
1084+ const struct btp_l2cap_listen_cmd * cp = cmd ;
1085+ uint16_t psm = sys_le16_to_cpu (cp -> psm );
1086+ uint16_t response = sys_le16_to_cpu (cp -> response );
1087+
1088+ return _listen (psm , cp -> transport , response , BTP_L2CAP_LISTEN_V2_MODE_NONE , 0 );
1089+ }
1090+
1091+ static uint8_t listen_v2 (const void * cmd , uint16_t cmd_len , void * rsp , uint16_t * rsp_len )
1092+ {
1093+ const struct btp_l2cap_listen_v2_cmd * cp = cmd ;
1094+ uint16_t psm = sys_le16_to_cpu (cp -> psm );
1095+ uint16_t response = sys_le16_to_cpu (cp -> response );
1096+ uint32_t options = sys_le32_to_cpu (cp -> options );
1097+
1098+ return _listen (psm , cp -> transport , response , cp -> mode , options );
10011099}
10021100
10031101static uint8_t credits (const void * cmd , uint16_t cmd_len ,
@@ -1122,6 +1220,11 @@ static const struct btp_handler handlers[] = {
11221220 .expect_len = sizeof (struct btp_l2cap_listen_cmd ),
11231221 .func = listen ,
11241222 },
1223+ {
1224+ .opcode = BTP_L2CAP_LISTEN_V2 ,
1225+ .expect_len = sizeof (struct btp_l2cap_listen_v2_cmd ),
1226+ .func = listen_v2 ,
1227+ },
11251228 {
11261229 .opcode = BTP_L2CAP_RECONFIGURE ,
11271230 .expect_len = BTP_HANDLER_LENGTH_VARIABLE ,
0 commit comments