Skip to content

Commit 895ba04

Browse files
makeshicfriedt
authored andcommitted
Bluetooth: AVCTP: Refactors the AVCTP to support multiple L2CAP PSMs
- This patch refactors the AVCTP layer to support multiple L2CAP PSMs - Introduced bt_avctp_server structure for dynamic L2CAP server registration and new server register apis - Added k_sem protected server list to support multiple AVCTP servers Signed-off-by: Make Shi <[email protected]>
1 parent 009114a commit 895ba04

File tree

2 files changed

+138
-80
lines changed

2 files changed

+138
-80
lines changed

subsys/bluetooth/host/classic/avctp.c

Lines changed: 85 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@
3131
LOG_MODULE_REGISTER(bt_avctp);
3232

3333
#define AVCTP_CHAN(_ch) CONTAINER_OF(_ch, struct bt_avctp, br_chan.chan)
34-
35-
static const struct bt_avctp_event_cb *event_cb;
34+
/* L2CAP Server list */
35+
static sys_slist_t avctp_l2cap_server = SYS_SLIST_STATIC_INIT(&avctp_l2cap_server);
36+
static struct k_sem avctp_server_lock;
3637

3738
static void avctp_l2cap_connected(struct bt_l2cap_chan *chan)
3839
{
@@ -80,7 +81,6 @@ static int avctp_l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
8081
struct bt_avctp *session = AVCTP_CHAN(chan);
8182
struct bt_avctp_header *hdr = (void *)buf->data;
8283
uint8_t tid;
83-
bt_avctp_pkt_type_t pkt_type;
8484
bt_avctp_cr_t cr;
8585
int err;
8686

@@ -90,46 +90,34 @@ static int avctp_l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
9090
}
9191

9292
tid = BT_AVCTP_HDR_GET_TRANSACTION_LABLE(hdr);
93-
pkt_type = BT_AVCTP_HDR_GET_PACKET_TYPE(hdr);
9493
cr = BT_AVCTP_HDR_GET_CR(hdr);
9594

96-
switch (pkt_type) {
97-
case BT_AVCTP_PKT_TYPE_SINGLE:
98-
break;
99-
case BT_AVCTP_PKT_TYPE_START:
100-
case BT_AVCTP_PKT_TYPE_CONTINUE:
101-
case BT_AVCTP_PKT_TYPE_END:
102-
default:
103-
LOG_ERR("fragmented AVCTP message is not supported, pkt_type = %d", pkt_type);
104-
return -EINVAL;
95+
LOG_DBG("AVCTP msg received, cr:0x%X, tid:0x%X, pid: 0x%04X",
96+
cr, tid, sys_be16_to_cpu(hdr->pid));
97+
98+
if (sys_be16_to_cpu(hdr->pid) == session->pid) {
99+
return session->ops->recv(session, buf);
105100
}
106101

107-
switch (hdr->pid) {
108-
#if defined(CONFIG_BT_AVRCP)
109-
case sys_cpu_to_be16(BT_SDP_AV_REMOTE_SVCLASS):
110-
break;
111-
#endif
112-
default:
113-
LOG_ERR("unsupported AVCTP PID received: 0x%04x", sys_be16_to_cpu(hdr->pid));
114-
if (cr == BT_AVCTP_CMD) {
115-
rsp = bt_avctp_create_pdu(session, BT_AVCTP_RESPONSE,
116-
BT_AVCTP_PKT_TYPE_SINGLE, BT_AVCTP_IPID_INVALID,
117-
tid, hdr->pid);
118-
if (!rsp) {
119-
return -ENOMEM;
120-
}
121-
122-
err = bt_avctp_send(session, rsp);
123-
if (err < 0) {
124-
net_buf_unref(rsp);
125-
LOG_ERR("AVCTP send fail, err = %d", err);
126-
return err;
127-
}
102+
LOG_ERR("unsupported AVCTP PID received: 0x%04x", sys_be16_to_cpu(hdr->pid));
103+
if (cr == BT_AVCTP_CMD) {
104+
rsp = bt_avctp_create_pdu(session, BT_AVCTP_RESPONSE,
105+
BT_AVCTP_PKT_TYPE_SINGLE, BT_AVCTP_IPID_INVALID,
106+
tid, hdr->pid);
107+
if (rsp == NULL) {
108+
__ASSERT(0, "Failed to create AVCTP response PDU");
109+
return -ENOMEM;
128110
}
129-
return 0; /* No need to report to the upper layer */
130-
}
131111

132-
return session->ops->recv(session, buf);
112+
err = bt_avctp_send(session, rsp);
113+
if (err < 0) {
114+
net_buf_unref(rsp);
115+
LOG_ERR("AVCTP send fail, err = %d", err);
116+
bt_avctp_disconnect(session);
117+
return err;
118+
}
119+
}
120+
return 0; /* No need to report to the upper layer */
133121
}
134122

135123
static const struct bt_l2cap_chan_ops ops = {
@@ -139,17 +127,14 @@ static const struct bt_l2cap_chan_ops ops = {
139127
.recv = avctp_l2cap_recv,
140128
};
141129

142-
int bt_avctp_connect(struct bt_conn *conn, struct bt_avctp *session)
130+
int bt_avctp_connect(struct bt_conn *conn, uint16_t psm, struct bt_avctp *session)
143131
{
144132
if (!session) {
145133
return -EINVAL;
146134
}
147135

148-
session->br_chan.rx.mtu = BT_L2CAP_RX_MTU;
149136
session->br_chan.chan.ops = &ops;
150-
session->br_chan.required_sec_level = BT_SECURITY_L2;
151-
152-
return bt_l2cap_chan_connect(conn, &session->br_chan.chan, BT_L2CAP_PSM_AVCTP);
137+
return bt_l2cap_chan_connect(conn, &session->br_chan.chan, psm);
153138
}
154139

155140
int bt_avctp_disconnect(struct bt_avctp *session)
@@ -163,6 +148,19 @@ int bt_avctp_disconnect(struct bt_avctp *session)
163148
return bt_l2cap_chan_disconnect(&session->br_chan.chan);
164149
}
165150

151+
void bt_avctp_set_header(struct bt_avctp_header *avctp_hdr, bt_avctp_cr_t cr,
152+
bt_avctp_pkt_type_t pkt_type, bt_avctp_ipid_t ipid,
153+
uint8_t tid, uint16_t pid)
154+
{
155+
LOG_DBG("");
156+
157+
BT_AVCTP_HDR_SET_TRANSACTION_LABLE(avctp_hdr, tid);
158+
BT_AVCTP_HDR_SET_PACKET_TYPE(avctp_hdr, pkt_type);
159+
BT_AVCTP_HDR_SET_CR(avctp_hdr, cr);
160+
BT_AVCTP_HDR_SET_IPID(avctp_hdr, ipid);
161+
avctp_hdr->pid = pid;
162+
}
163+
166164
struct net_buf *bt_avctp_create_pdu(struct bt_avctp *session, bt_avctp_cr_t cr,
167165
bt_avctp_pkt_type_t pkt_type, bt_avctp_ipid_t ipid,
168166
uint8_t tid, uint16_t pid)
@@ -179,11 +177,7 @@ struct net_buf *bt_avctp_create_pdu(struct bt_avctp *session, bt_avctp_cr_t cr,
179177
}
180178

181179
hdr = net_buf_add(buf, sizeof(*hdr));
182-
BT_AVCTP_HDR_SET_TRANSACTION_LABLE(hdr, tid);
183-
BT_AVCTP_HDR_SET_PACKET_TYPE(hdr, pkt_type);
184-
BT_AVCTP_HDR_SET_CR(hdr, cr);
185-
BT_AVCTP_HDR_SET_IPID(hdr, ipid);
186-
hdr->pid = pid;
180+
bt_avctp_set_header(hdr, cr, pkt_type, ipid, tid, pid);
187181

188182
LOG_DBG("cr:0x%lX, tid:0x%02lX", BT_AVCTP_HDR_GET_CR(hdr),
189183
BT_AVCTP_HDR_GET_TRANSACTION_LABLE(hdr));
@@ -195,63 +189,78 @@ int bt_avctp_send(struct bt_avctp *session, struct net_buf *buf)
195189
return bt_l2cap_chan_send(&session->br_chan.chan, buf);
196190
}
197191

198-
int bt_avctp_register(const struct bt_avctp_event_cb *cb)
199-
{
200-
LOG_DBG("");
201-
202-
if (event_cb) {
203-
return -EALREADY;
204-
}
205-
206-
event_cb = cb;
207-
208-
return 0;
209-
}
210-
211192
static int avctp_l2cap_accept(struct bt_conn *conn, struct bt_l2cap_server *server,
212193
struct bt_l2cap_chan **chan)
213194
{
214195
struct bt_avctp *session = NULL;
196+
struct bt_avctp_server *avctp_server;
215197
int err;
216198

217199
LOG_DBG("conn %p", conn);
218200

219-
if (!event_cb) {
220-
LOG_WRN("AVCTP server is unsupported");
221-
return -ENOTSUP;
201+
avctp_server = CONTAINER_OF(server, struct bt_avctp_server, l2cap);
202+
203+
k_sem_take(&avctp_server_lock, K_FOREVER);
204+
205+
if (!sys_slist_find(&avctp_l2cap_server, &avctp_server->node, NULL)) {
206+
LOG_WRN("Invalid l2cap server");
207+
k_sem_give(&avctp_server_lock);
208+
return -EINVAL;
222209
}
223210

211+
k_sem_give(&avctp_server_lock);
212+
224213
/* Get the AVCTP session from upper layer */
225-
err = event_cb->accept(conn, &session);
214+
err = avctp_server->accept(conn, &session);
226215
if (err < 0) {
227-
LOG_ERR("Get the AVCTP session failed %d", err);
216+
LOG_ERR("Incoming connection rejected");
228217
return err;
229218
}
230219

231-
session->br_chan.rx.mtu = BT_L2CAP_RX_MTU;
232-
session->br_chan.psm = BT_L2CAP_PSM_AVCTP;
233220
session->br_chan.chan.ops = &ops;
234221
*chan = &session->br_chan.chan;
235222

236223
return 0;
237224
}
238225

239-
int bt_avctp_init(void)
226+
int bt_avctp_server_register(struct bt_avctp_server *server)
240227
{
241228
int err;
242-
static struct bt_l2cap_server avctp_l2cap = {
243-
.psm = BT_L2CAP_PSM_AVCTP,
244-
.sec_level = BT_SECURITY_L2,
245-
.accept = avctp_l2cap_accept,
246-
};
247-
248229
LOG_DBG("");
249230

250-
/* Register AVCTP PSM with L2CAP */
251-
err = bt_l2cap_br_server_register(&avctp_l2cap);
231+
if ((server == NULL) || (server->accept == NULL)) {
232+
LOG_DBG("Invalid parameter");
233+
return -EINVAL;
234+
}
235+
236+
k_sem_take(&avctp_server_lock, K_FOREVER);
237+
238+
if (sys_slist_find(&avctp_l2cap_server, &server->node, NULL)) {
239+
LOG_WRN("L2CAP server has been registered");
240+
k_sem_give(&avctp_server_lock);
241+
return -EEXIST;
242+
}
243+
244+
server->l2cap.accept = avctp_l2cap_accept;
245+
err = bt_l2cap_br_server_register(&server->l2cap);
252246
if (err < 0) {
253247
LOG_ERR("AVCTP L2CAP registration failed %d", err);
248+
k_sem_give(&avctp_server_lock);
249+
return err;
254250
}
255251

252+
LOG_DBG("Register L2CAP server %p", server);
253+
sys_slist_append(&avctp_l2cap_server, &server->node);
254+
255+
k_sem_give(&avctp_server_lock);
256+
256257
return err;
257258
}
259+
260+
int bt_avctp_init(void)
261+
{
262+
LOG_DBG("Initializing AVCTP");
263+
/* Locking semaphore initialized to 1 (unlocked) */
264+
k_sem_init(&avctp_server_lock, 1, 1);
265+
return 0;
266+
}

subsys/bluetooth/host/classic/avctp_internal.h

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
* SPDX-License-Identifier: Apache-2.0
1010
*/
1111

12-
#define BT_L2CAP_PSM_AVCTP 0x0017
13-
1412
typedef enum __packed {
1513
BT_AVCTP_IPID_NONE = 0b0,
1614
BT_AVCTP_IPID_INVALID = 0b1,
@@ -82,6 +80,52 @@ struct bt_avctp_ops_cb {
8280
struct bt_avctp {
8381
struct bt_l2cap_br_chan br_chan;
8482
const struct bt_avctp_ops_cb *ops;
83+
uint16_t pid; /** Profile Identifier */
84+
};
85+
86+
/**
87+
* @brief AVCTP L2CAP Server structure
88+
*
89+
* This structure defines the L2CAP server used for AVCTP over L2CAP transport.
90+
*/
91+
struct bt_avctp_server {
92+
/**
93+
* @brief L2CAP server parameters
94+
*
95+
* This field is used to register the L2CAP server. The `psm` field can be set
96+
* to a specific value (not recommended), or set to 0 to allow automatic PSM
97+
* allocation during registration via @ref bt_avctp_server_register.
98+
*
99+
* The `sec_level` field specifies the minimum required security level.
100+
*
101+
* @note The `struct bt_l2cap_server::accept` callback of `l2cap` can not be used
102+
* by AVCTP applications. Instead, use the `struct bt_avctp_server::accept`
103+
* callback defined in this structure.
104+
*/
105+
struct bt_l2cap_server l2cap;
106+
107+
/**
108+
* @brief Accept callback for incoming AVCTP connections
109+
*
110+
* This callback is invoked when a new incoming AVCTP connection is received.
111+
* The application is responsible for authorizing the connection and allocating
112+
* a new AVCTP session object.
113+
*
114+
* @warning The caller must ensure that the parent object of the AVCTP session
115+
* is properly zero-initialized before use.
116+
*
117+
* @param conn The Bluetooth connection requesting authorization.
118+
* @param session Pointer to receive the allocated AVCTP session object.
119+
*
120+
* @retval 0 Success.
121+
* @retval -ENOMEM No available space for a new session.
122+
* @retval -EACCES Connection not authorized by the application.
123+
* @retval -EPERM Encryption key size is insufficient.
124+
*/
125+
int (*accept)(struct bt_conn *conn, struct bt_avctp **session);
126+
127+
/** @brief Internal node for list management */
128+
sys_snode_t node;
85129
};
86130

87131
struct bt_avctp_event_cb {
@@ -92,10 +136,10 @@ struct bt_avctp_event_cb {
92136
int bt_avctp_init(void);
93137

94138
/* Application register with AVCTP layer */
95-
int bt_avctp_register(const struct bt_avctp_event_cb *cb);
139+
int bt_avctp_server_register(struct bt_avctp_server *server);
96140

97141
/* AVCTP connect */
98-
int bt_avctp_connect(struct bt_conn *conn, struct bt_avctp *session);
142+
int bt_avctp_connect(struct bt_conn *conn, uint16_t psm, struct bt_avctp *session);
99143

100144
/* AVCTP disconnect */
101145
int bt_avctp_disconnect(struct bt_avctp *session);
@@ -105,5 +149,10 @@ struct net_buf *bt_avctp_create_pdu(struct bt_avctp *session, bt_avctp_cr_t cr,
105149
bt_avctp_pkt_type_t pkt_type, bt_avctp_ipid_t ipid,
106150
uint8_t tid, uint16_t pid);
107151

152+
/* Set AVCTP header */
153+
void bt_avctp_set_header(struct bt_avctp_header *avctp_hdr, bt_avctp_cr_t cr,
154+
bt_avctp_pkt_type_t pkt_type, bt_avctp_ipid_t ipid,
155+
uint8_t tid, uint16_t pid);
156+
108157
/* Send AVCTP PDU */
109158
int bt_avctp_send(struct bt_avctp *session, struct net_buf *buf);

0 commit comments

Comments
 (0)