1 /** @file
2 * @brief Audio Video Control Transport Protocol
3 */
4
5 /*
6 * Copyright (c) 2015-2016 Intel Corporation
7 * Copyright (C) 2024 Xiaomi Corporation
8 *
9 * SPDX-License-Identifier: Apache-2.0
10 */
11
12 #include <string.h>
13 #include <strings.h>
14 #include <errno.h>
15 #include <zephyr/sys/atomic.h>
16 #include <zephyr/sys/byteorder.h>
17 #include <zephyr/sys/util.h>
18
19 #include <zephyr/bluetooth/hci.h>
20 #include <zephyr/bluetooth/bluetooth.h>
21 #include <zephyr/bluetooth/l2cap.h>
22 #include <zephyr/bluetooth/classic/sdp.h>
23
24 #include "avctp_internal.h"
25 #include "host/hci_core.h"
26 #include "host/conn_internal.h"
27 #include "l2cap_br_internal.h"
28
29 #define LOG_LEVEL CONFIG_BT_AVCTP_LOG_LEVEL
30 #include <zephyr/logging/log.h>
31 LOG_MODULE_REGISTER(bt_avctp);
32
33 #define AVCTP_CHAN(_ch) CONTAINER_OF(_ch, struct bt_avctp, br_chan.chan)
34
35 static const struct bt_avctp_event_cb *event_cb;
36
avctp_l2cap_connected(struct bt_l2cap_chan * chan)37 static void avctp_l2cap_connected(struct bt_l2cap_chan *chan)
38 {
39 struct bt_avctp *session;
40
41 if (!chan) {
42 LOG_ERR("Invalid AVCTP chan");
43 return;
44 }
45
46 session = AVCTP_CHAN(chan);
47 LOG_DBG("chan %p session %p", chan, session);
48
49 if (session->ops && session->ops->connected) {
50 session->ops->connected(session);
51 }
52 }
53
avctp_l2cap_disconnected(struct bt_l2cap_chan * chan)54 static void avctp_l2cap_disconnected(struct bt_l2cap_chan *chan)
55 {
56 struct bt_avctp *session;
57
58 if (!chan) {
59 LOG_ERR("Invalid AVCTP chan");
60 return;
61 }
62
63 session = AVCTP_CHAN(chan);
64 LOG_DBG("chan %p session %p", chan, session);
65 session->br_chan.chan.conn = NULL;
66
67 if (session->ops && session->ops->disconnected) {
68 session->ops->disconnected(session);
69 }
70 }
71
avctp_l2cap_encrypt_changed(struct bt_l2cap_chan * chan,uint8_t status)72 static void avctp_l2cap_encrypt_changed(struct bt_l2cap_chan *chan, uint8_t status)
73 {
74 LOG_DBG("");
75 }
76
avctp_l2cap_recv(struct bt_l2cap_chan * chan,struct net_buf * buf)77 static int avctp_l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
78 {
79 struct net_buf *rsp;
80 struct bt_avctp *session = AVCTP_CHAN(chan);
81 struct bt_avctp_header *hdr = (void *)buf->data;
82 uint8_t tid;
83 bt_avctp_pkt_type_t pkt_type;
84 bt_avctp_cr_t cr;
85 int err;
86
87 if (buf->len < sizeof(*hdr)) {
88 LOG_ERR("invalid AVCTP header received");
89 return -EINVAL;
90 }
91
92 tid = BT_AVCTP_HDR_GET_TRANSACTION_LABLE(hdr);
93 pkt_type = BT_AVCTP_HDR_GET_PACKET_TYPE(hdr);
94 cr = BT_AVCTP_HDR_GET_CR(hdr);
95
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;
105 }
106
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 }
128 }
129 return 0; /* No need to report to the upper layer */
130 }
131
132 return session->ops->recv(session, buf);
133 }
134
135 static const struct bt_l2cap_chan_ops ops = {
136 .connected = avctp_l2cap_connected,
137 .disconnected = avctp_l2cap_disconnected,
138 .encrypt_change = avctp_l2cap_encrypt_changed,
139 .recv = avctp_l2cap_recv,
140 };
141
bt_avctp_connect(struct bt_conn * conn,struct bt_avctp * session)142 int bt_avctp_connect(struct bt_conn *conn, struct bt_avctp *session)
143 {
144 if (!session) {
145 return -EINVAL;
146 }
147
148 session->br_chan.rx.mtu = BT_L2CAP_RX_MTU;
149 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);
153 }
154
bt_avctp_disconnect(struct bt_avctp * session)155 int bt_avctp_disconnect(struct bt_avctp *session)
156 {
157 if (!session) {
158 return -EINVAL;
159 }
160
161 LOG_DBG("session %p", session);
162
163 return bt_l2cap_chan_disconnect(&session->br_chan.chan);
164 }
165
bt_avctp_create_pdu(struct bt_avctp * session,bt_avctp_cr_t cr,bt_avctp_pkt_type_t pkt_type,bt_avctp_ipid_t ipid,uint8_t tid,uint16_t pid)166 struct net_buf *bt_avctp_create_pdu(struct bt_avctp *session, bt_avctp_cr_t cr,
167 bt_avctp_pkt_type_t pkt_type, bt_avctp_ipid_t ipid,
168 uint8_t tid, uint16_t pid)
169 {
170 struct net_buf *buf;
171 struct bt_avctp_header *hdr;
172
173 LOG_DBG("");
174
175 buf = bt_l2cap_create_pdu(NULL, 0);
176 if (!buf) {
177 LOG_ERR("No buff available");
178 return buf;
179 }
180
181 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;
187
188 LOG_DBG("cr:0x%lX, tid:0x%02lX", BT_AVCTP_HDR_GET_CR(hdr),
189 BT_AVCTP_HDR_GET_TRANSACTION_LABLE(hdr));
190 return buf;
191 }
192
bt_avctp_send(struct bt_avctp * session,struct net_buf * buf)193 int bt_avctp_send(struct bt_avctp *session, struct net_buf *buf)
194 {
195 return bt_l2cap_chan_send(&session->br_chan.chan, buf);
196 }
197
bt_avctp_register(const struct bt_avctp_event_cb * cb)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
avctp_l2cap_accept(struct bt_conn * conn,struct bt_l2cap_server * server,struct bt_l2cap_chan ** chan)211 static int avctp_l2cap_accept(struct bt_conn *conn, struct bt_l2cap_server *server,
212 struct bt_l2cap_chan **chan)
213 {
214 struct bt_avctp *session = NULL;
215 int err;
216
217 LOG_DBG("conn %p", conn);
218
219 if (!event_cb) {
220 LOG_WRN("AVCTP server is unsupported");
221 return -ENOTSUP;
222 }
223
224 /* Get the AVCTP session from upper layer */
225 err = event_cb->accept(conn, &session);
226 if (err < 0) {
227 LOG_ERR("Get the AVCTP session failed %d", err);
228 return err;
229 }
230
231 session->br_chan.rx.mtu = BT_L2CAP_RX_MTU;
232 session->br_chan.psm = BT_L2CAP_PSM_AVCTP;
233 session->br_chan.chan.ops = &ops;
234 *chan = &session->br_chan.chan;
235
236 return 0;
237 }
238
bt_avctp_init(void)239 int bt_avctp_init(void)
240 {
241 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
248 LOG_DBG("");
249
250 /* Register AVCTP PSM with L2CAP */
251 err = bt_l2cap_br_server_register(&avctp_l2cap);
252 if (err < 0) {
253 LOG_ERR("AVCTP L2CAP registration failed %d", err);
254 }
255
256 return err;
257 }
258