1 /*
2 * Copyright (c) 2020 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/types.h>
8 #include <stddef.h>
9 #include <string.h>
10 #include <errno.h>
11 #include <sys/printk.h>
12 #include <sys/byteorder.h>
13 #include <zephyr.h>
14 #include <init.h>
15
16 #include <net/buf.h>
17
18 #include "ots_l2cap_internal.h"
19
20 #include <logging/log.h>
21
22 LOG_MODULE_DECLARE(bt_ots, CONFIG_BT_OTS_LOG_LEVEL);
23
24 /* According to BLE specification Assigned Numbers that are used in the
25 * Logical Link Control for protocol/service multiplexers.
26 */
27 #define BT_GATT_OTS_L2CAP_PSM 0x0025
28
29
30 NET_BUF_POOL_FIXED_DEFINE(ot_chan_tx_pool, 1,
31 BT_L2CAP_SDU_BUF_SIZE(CONFIG_BT_OTS_L2CAP_CHAN_TX_MTU),
32 NULL);
33
34 #if (CONFIG_BT_OTS_L2CAP_CHAN_RX_MTU > BT_L2CAP_SDU_RX_MTU)
35 NET_BUF_POOL_FIXED_DEFINE(ot_chan_rx_pool, 1, CONFIG_BT_OTS_L2CAP_CHAN_RX_MTU,
36 NULL);
37 #endif
38
39 /* List of Object Transfer Channels. */
40 static sys_slist_t channels;
41
ots_l2cap_send(struct bt_gatt_ots_l2cap * l2cap_ctx)42 static int ots_l2cap_send(struct bt_gatt_ots_l2cap *l2cap_ctx)
43 {
44 int ret;
45 struct net_buf *buf;
46 uint32_t len;
47
48 /* Calculate maximum length of data chunk. */
49 len = MIN(l2cap_ctx->ot_chan.tx.mtu, CONFIG_BT_OTS_L2CAP_CHAN_TX_MTU);
50 len = MIN(len, l2cap_ctx->tx.len - l2cap_ctx->tx.len_sent);
51
52 /* Prepare buffer for sending. */
53 buf = net_buf_alloc(&ot_chan_tx_pool, K_FOREVER);
54 net_buf_reserve(buf, BT_L2CAP_SDU_CHAN_SEND_RESERVE);
55 net_buf_add_mem(buf, &l2cap_ctx->tx.data[l2cap_ctx->tx.len_sent], len);
56
57 ret = bt_l2cap_chan_send(&l2cap_ctx->ot_chan.chan, buf);
58 if (ret < 0) {
59 LOG_ERR("Unable to send data over CoC: %d", ret);
60 net_buf_unref(buf);
61
62 return -ENOEXEC;
63 }
64
65 /* Mark that L2CAP TX was accepted. */
66 l2cap_ctx->tx.len_sent += len;
67
68 LOG_DBG("Sending TX chunk with %d bytes on L2CAP CoC", len);
69
70 return 0;
71 }
72
73 #if (CONFIG_BT_OTS_L2CAP_CHAN_RX_MTU > BT_L2CAP_SDU_RX_MTU)
l2cap_alloc_buf(struct bt_l2cap_chan * chan)74 static struct net_buf *l2cap_alloc_buf(struct bt_l2cap_chan *chan)
75 {
76 LOG_DBG("Channel %p allocating buffer", chan);
77
78 return net_buf_alloc(&ot_chan_rx_pool, K_FOREVER);
79 }
80 #endif
81
82
l2cap_sent(struct bt_l2cap_chan * chan)83 static void l2cap_sent(struct bt_l2cap_chan *chan)
84 {
85 struct bt_gatt_ots_l2cap *l2cap_ctx;
86
87 LOG_DBG("Outgoing data channel %p transmitted", chan);
88
89 l2cap_ctx = CONTAINER_OF(chan, struct bt_gatt_ots_l2cap, ot_chan);
90
91 /* Ongoing TX - sending next chunk. */
92 if (l2cap_ctx->tx.len != l2cap_ctx->tx.len_sent) {
93 ots_l2cap_send(l2cap_ctx);
94
95 return;
96 }
97
98 /* TX completed - notify upper layers and clean up. */
99 memset(&l2cap_ctx->tx, 0, sizeof(l2cap_ctx->tx));
100
101 LOG_DBG("Scheduled TX on L2CAP CoC is complete");
102
103 if (l2cap_ctx->tx_done) {
104 l2cap_ctx->tx_done(l2cap_ctx, chan->conn);
105 }
106 }
107
l2cap_recv(struct bt_l2cap_chan * chan,struct net_buf * buf)108 static int l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
109 {
110 struct bt_gatt_ots_l2cap *l2cap_ctx;
111
112 LOG_DBG("Incoming data channel %p received", chan);
113
114 l2cap_ctx = CONTAINER_OF(chan, struct bt_gatt_ots_l2cap, ot_chan);
115
116 if (!l2cap_ctx->rx_done) {
117 return -ENODEV;
118 }
119
120 return l2cap_ctx->rx_done(l2cap_ctx, chan->conn, buf);
121 }
122
l2cap_status(struct bt_l2cap_chan * chan,atomic_t * status)123 static void l2cap_status(struct bt_l2cap_chan *chan, atomic_t *status)
124 {
125 LOG_DBG("Channel %p status %u", chan, *status);
126 }
127
l2cap_connected(struct bt_l2cap_chan * chan)128 static void l2cap_connected(struct bt_l2cap_chan *chan)
129 {
130 LOG_DBG("Channel %p connected", chan);
131 }
132
l2cap_disconnected(struct bt_l2cap_chan * chan)133 static void l2cap_disconnected(struct bt_l2cap_chan *chan)
134 {
135 struct bt_gatt_ots_l2cap *l2cap_ctx;
136
137 LOG_DBG("Channel %p disconnected", chan);
138
139 l2cap_ctx = CONTAINER_OF(chan, struct bt_gatt_ots_l2cap, ot_chan);
140
141 if (l2cap_ctx->closed) {
142 l2cap_ctx->closed(l2cap_ctx, chan->conn);
143 }
144 }
145
146 static const struct bt_l2cap_chan_ops l2cap_ops = {
147 #if (CONFIG_BT_OTS_L2CAP_CHAN_RX_MTU > BT_L2CAP_SDU_RX_MTU)
148 .alloc_buf = l2cap_alloc_buf,
149 #endif
150 .sent = l2cap_sent,
151 .recv = l2cap_recv,
152 .status = l2cap_status,
153 .connected = l2cap_connected,
154 .disconnected = l2cap_disconnected,
155 };
156
l2cap_chan_init(struct bt_l2cap_le_chan * chan)157 static inline void l2cap_chan_init(struct bt_l2cap_le_chan *chan)
158 {
159 chan->rx.mtu = CONFIG_BT_OTS_L2CAP_CHAN_RX_MTU;
160 chan->chan.ops = &l2cap_ops;
161
162 LOG_DBG("RX MTU set to %u", chan->rx.mtu);
163 }
164
l2cap_accept(struct bt_conn * conn,struct bt_l2cap_chan ** chan)165 static int l2cap_accept(struct bt_conn *conn, struct bt_l2cap_chan **chan)
166 {
167 struct bt_gatt_ots_l2cap *l2cap_ctx;
168
169 LOG_DBG("Incoming conn %p", (void *)conn);
170
171 SYS_SLIST_FOR_EACH_CONTAINER(&channels, l2cap_ctx, node) {
172 if (l2cap_ctx->ot_chan.chan.conn) {
173 continue;
174 }
175
176 l2cap_chan_init(&l2cap_ctx->ot_chan);
177 memset(&l2cap_ctx->tx, 0, sizeof(l2cap_ctx->tx));
178
179 *chan = &l2cap_ctx->ot_chan.chan;
180
181 return 0;
182 }
183
184 return -ENOMEM;
185 }
186
187 static struct bt_l2cap_server l2cap_server = {
188 .psm = BT_GATT_OTS_L2CAP_PSM,
189 .accept = l2cap_accept,
190 };
191
bt_gatt_ots_l2cap_init(const struct device * arg)192 static int bt_gatt_ots_l2cap_init(const struct device *arg)
193 {
194 int err;
195
196 sys_slist_init(&channels);
197
198 err = bt_l2cap_server_register(&l2cap_server);
199 if (err) {
200 LOG_ERR("Unable to register OTS PSM");
201 return err;
202 }
203
204 LOG_DBG("Initialized OTS L2CAP");
205
206 return 0;
207 }
208
bt_gatt_ots_l2cap_is_open(struct bt_gatt_ots_l2cap * l2cap_ctx,struct bt_conn * conn)209 bool bt_gatt_ots_l2cap_is_open(struct bt_gatt_ots_l2cap *l2cap_ctx,
210 struct bt_conn *conn)
211 {
212 return (l2cap_ctx->ot_chan.chan.conn == conn);
213 }
214
bt_gatt_ots_l2cap_send(struct bt_gatt_ots_l2cap * l2cap_ctx,uint8_t * data,uint32_t len)215 int bt_gatt_ots_l2cap_send(struct bt_gatt_ots_l2cap *l2cap_ctx,
216 uint8_t *data, uint32_t len)
217 {
218 int err;
219
220 if (l2cap_ctx->tx.len != 0) {
221 LOG_ERR("L2CAP TX in progress");
222
223 return -EAGAIN;
224 }
225
226 l2cap_ctx->tx.data = data;
227 l2cap_ctx->tx.len = len;
228
229 LOG_DBG("Starting TX on L2CAP CoC with %d byte packet", len);
230
231 err = ots_l2cap_send(l2cap_ctx);
232 if (err) {
233 LOG_ERR("Unable to send data over CoC: %d", err);
234
235 return err;
236 }
237
238 return 0;
239 }
240
bt_gatt_ots_l2cap_register(struct bt_gatt_ots_l2cap * l2cap_ctx)241 int bt_gatt_ots_l2cap_register(struct bt_gatt_ots_l2cap *l2cap_ctx)
242 {
243 sys_slist_append(&channels, &l2cap_ctx->node);
244
245 return 0;
246 }
247
bt_gatt_ots_l2cap_unregister(struct bt_gatt_ots_l2cap * l2cap_ctx)248 int bt_gatt_ots_l2cap_unregister(struct bt_gatt_ots_l2cap *l2cap_ctx)
249 {
250 sys_slist_find_and_remove(&channels, &l2cap_ctx->node);
251
252 return 0;
253 }
254
bt_gatt_ots_l2cap_disconnect(struct bt_gatt_ots_l2cap * l2cap_ctx)255 int bt_gatt_ots_l2cap_disconnect(struct bt_gatt_ots_l2cap *l2cap_ctx)
256 {
257 return bt_l2cap_chan_disconnect(&l2cap_ctx->ot_chan.chan);
258 }
259
260 SYS_INIT(bt_gatt_ots_l2cap_init, APPLICATION,
261 CONFIG_APPLICATION_INIT_PRIORITY);
262