1 /* goep.c - Bluetooth Generic Object Exchange Profile handling */
2
3 /*
4 * Copyright 2024-2025 NXP
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <errno.h>
10 #include <zephyr/types.h>
11 #include <stddef.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <zephyr/sys/byteorder.h>
15 #include <zephyr/kernel.h>
16
17 #include <zephyr/bluetooth/hci.h>
18 #include <zephyr/bluetooth/bluetooth.h>
19 #include <zephyr/bluetooth/conn.h>
20 #include <zephyr/bluetooth/l2cap.h>
21 #include <zephyr/bluetooth/classic/rfcomm.h>
22 #include <zephyr/bluetooth/classic/sdp.h>
23 #include <zephyr/bluetooth/classic/goep.h>
24
25 #include "host/conn_internal.h"
26 #include "l2cap_br_internal.h"
27 #include "rfcomm_internal.h"
28 #include "obex_internal.h"
29
30 #define LOG_LEVEL CONFIG_BT_GOEP_LOG_LEVEL
31 #include <zephyr/logging/log.h>
32 LOG_MODULE_REGISTER(bt_goep);
33
34 #define GOEP_MIN_MTU BT_OBEX_MIN_MTU
35
36 /* RFCOMM Server list */
37 static sys_slist_t goep_rfcomm_server = SYS_SLIST_STATIC_INIT(&goep_rfcomm_server);
38
goep_rfcomm_recv(struct bt_rfcomm_dlc * dlc,struct net_buf * buf)39 static void goep_rfcomm_recv(struct bt_rfcomm_dlc *dlc, struct net_buf *buf)
40 {
41 struct bt_goep *goep = CONTAINER_OF(dlc, struct bt_goep, _transport.dlc);
42 int err;
43
44 err = bt_obex_recv(&goep->obex, buf);
45 if (err) {
46 LOG_WRN("Fail to handle OBEX packet (err %d)", err);
47 }
48 }
49
goep_rfcomm_connected(struct bt_rfcomm_dlc * dlc)50 static void goep_rfcomm_connected(struct bt_rfcomm_dlc *dlc)
51 {
52 struct bt_goep *goep = CONTAINER_OF(dlc, struct bt_goep, _transport.dlc);
53 int err;
54
55 LOG_DBG("RFCOMM %p connected", dlc);
56
57 if (dlc->mtu < GOEP_MIN_MTU) {
58 LOG_WRN("Invalid MTU %d", dlc->mtu);
59 bt_rfcomm_dlc_disconnect(dlc);
60 return;
61 }
62 goep->obex.rx.mtu = dlc->mtu;
63 goep->obex.tx.mtu = dlc->mtu;
64
65 /* Set MOPL of RX to MTU by default */
66 goep->obex.rx.mopl = dlc->mtu;
67 /* Set MOPL of TX to MTU by default to avoid the OBEX connect req cannot be sent. */
68 goep->obex.tx.mopl = dlc->mtu;
69
70 atomic_set(&goep->_state, BT_GOEP_TRANSPORT_CONNECTED);
71
72 err = bt_obex_transport_connected(&goep->obex);
73 if (err) {
74 LOG_WRN("Notify OBEX (err %d). Disconnecting transport...", err);
75 bt_rfcomm_dlc_disconnect(dlc);
76 return;
77 }
78
79 if (goep->transport_ops->connected) {
80 goep->transport_ops->connected(goep->_acl, goep);
81 }
82 }
83
goep_rfcomm_disconnected(struct bt_rfcomm_dlc * dlc)84 static void goep_rfcomm_disconnected(struct bt_rfcomm_dlc *dlc)
85 {
86 struct bt_goep *goep = CONTAINER_OF(dlc, struct bt_goep, _transport.dlc);
87 int err;
88
89 LOG_DBG("RFCOMM %p disconnected", dlc);
90
91 atomic_set(&goep->_state, BT_GOEP_TRANSPORT_DISCONNECTED);
92
93 err = bt_obex_transport_disconnected(&goep->obex);
94 if (err) {
95 LOG_WRN("Notify OBEX (err %d).", err);
96 }
97
98 if (goep->transport_ops->disconnected) {
99 goep->transport_ops->disconnected(goep);
100 }
101 }
102
103 static struct bt_rfcomm_dlc_ops goep_rfcomm_ops = {
104 .recv = goep_rfcomm_recv,
105 .connected = goep_rfcomm_connected,
106 .disconnected = goep_rfcomm_disconnected,
107 };
108
goep_rfcomm_send(struct bt_obex * obex,struct net_buf * buf)109 static int goep_rfcomm_send(struct bt_obex *obex, struct net_buf *buf)
110 {
111 struct bt_goep *goep = CONTAINER_OF(obex, struct bt_goep, obex);
112 int err;
113
114 if (goep->_goep_v2) {
115 LOG_WRN("Invalid transport");
116 return -EINVAL;
117 }
118
119 if (buf->len > obex->tx.mtu) {
120 LOG_WRN("Packet size exceeds MTU");
121 return -EMSGSIZE;
122 }
123
124 if (net_buf_tailroom(buf) < BT_RFCOMM_FCS_SIZE) {
125 LOG_WRN("No tailroom for RFCOMM FCS field");
126 return -EMSGSIZE;
127 }
128
129 err = bt_rfcomm_dlc_send(&goep->_transport.dlc, buf);
130 if (err < 0) {
131 return err;
132 }
133
134 return 0;
135 }
136
goep_rfcomm_alloc_buf(struct bt_obex * obex,struct net_buf_pool * pool)137 static struct net_buf *goep_rfcomm_alloc_buf(struct bt_obex *obex, struct net_buf_pool *pool)
138 {
139 struct bt_goep *goep = CONTAINER_OF(obex, struct bt_goep, obex);
140
141 if (goep->_goep_v2) {
142 LOG_WRN("Invalid transport");
143 return NULL;
144 }
145
146 return bt_goep_create_pdu(goep, pool);
147 }
148
goep_rfcomm_disconnect(struct bt_obex * obex)149 static int goep_rfcomm_disconnect(struct bt_obex *obex)
150 {
151 struct bt_goep *goep = CONTAINER_OF(obex, struct bt_goep, obex);
152
153 if (goep->_goep_v2) {
154 LOG_WRN("Invalid transport");
155 return -EINVAL;
156 }
157
158 return bt_rfcomm_dlc_disconnect(&goep->_transport.dlc);
159 }
160
161 static const struct bt_obex_transport_ops goep_rfcomm_transport_ops = {
162 .alloc_buf = goep_rfcomm_alloc_buf,
163 .send = goep_rfcomm_send,
164 .disconnect = goep_rfcomm_disconnect,
165 };
166
goep_rfcomm_accept(struct bt_conn * conn,struct bt_rfcomm_server * server,struct bt_rfcomm_dlc ** dlc)167 static int goep_rfcomm_accept(struct bt_conn *conn, struct bt_rfcomm_server *server,
168 struct bt_rfcomm_dlc **dlc)
169 {
170 struct bt_goep_transport_rfcomm_server *rfcomm_server;
171 struct bt_goep *goep;
172 uint32_t mtu;
173 uint32_t hdr_size;
174 int err;
175
176 rfcomm_server = CONTAINER_OF(server, struct bt_goep_transport_rfcomm_server, rfcomm);
177
178 if (!sys_slist_find(&goep_rfcomm_server, &rfcomm_server->node, NULL)) {
179 LOG_WRN("Invalid rfcomm server");
180 return -ENOMEM;
181 }
182
183 err = rfcomm_server->accept(conn, rfcomm_server, &goep);
184 if (err) {
185 LOG_DBG("Incoming connection rejected");
186 return err;
187 }
188
189 if (!goep || !goep->transport_ops || !goep->obex.server_ops ||
190 !goep->obex.server_ops->connect || !goep->obex.server_ops->disconnect) {
191 LOG_DBG("Invalid parameter");
192 return -EINVAL;
193 }
194
195 hdr_size = sizeof(struct bt_l2cap_hdr);
196 hdr_size += BT_RFCOMM_HDR_SIZE + BT_RFCOMM_FCS_SIZE;
197
198 mtu = CONFIG_BT_GOEP_RFCOMM_MTU - hdr_size;
199 /* Use default MTU if it is not given */
200 if (!goep->obex.rx.mtu) {
201 goep->obex.rx.mtu = mtu;
202 }
203
204 if (goep->obex.rx.mtu < GOEP_MIN_MTU) {
205 LOG_WRN("GOEP RFCOMM MTU less than minimum size (%d < %d)", goep->obex.rx.mtu,
206 GOEP_MIN_MTU);
207 goep->obex.rx.mtu = GOEP_MIN_MTU;
208 }
209
210 if (goep->obex.rx.mtu > mtu) {
211 LOG_WRN("GOEP RFCOMM MTU exceeds maximum size (%d > %d)", goep->obex.rx.mtu, mtu);
212 goep->obex.rx.mtu = mtu;
213 }
214
215 err = bt_obex_reg_transport(&goep->obex, &goep_rfcomm_transport_ops);
216 if (err) {
217 LOG_WRN("Fail to reg transport ops");
218 return err;
219 }
220
221 goep->_goep_v2 = false;
222 goep->_acl = conn;
223 *dlc = &goep->_transport.dlc;
224 goep->_transport.dlc.mtu = goep->obex.rx.mtu;
225 goep->_transport.dlc.ops = &goep_rfcomm_ops;
226 goep->_transport.dlc.required_sec_level = BT_SECURITY_L2;
227
228 atomic_set(&goep->_state, BT_GOEP_TRANSPORT_CONNECTING);
229
230 return 0;
231 }
232
bt_goep_transport_rfcomm_server_register(struct bt_goep_transport_rfcomm_server * server)233 int bt_goep_transport_rfcomm_server_register(struct bt_goep_transport_rfcomm_server *server)
234 {
235 int err;
236
237 if (!server || !server->accept) {
238 LOG_DBG("Invalid parameter");
239 return -EINVAL;
240 }
241
242 if (sys_slist_find(&goep_rfcomm_server, &server->node, NULL)) {
243 LOG_WRN("RFCOMM server has been registered");
244 return -EEXIST;
245 }
246
247 server->rfcomm.accept = goep_rfcomm_accept;
248 err = bt_rfcomm_server_register(&server->rfcomm);
249 if (err) {
250 LOG_WRN("Fail to register RFCOMM Server %p", server);
251 return err;
252 }
253
254 LOG_DBG("Register RFCOMM server %p", server);
255 sys_slist_append(&goep_rfcomm_server, &server->node);
256
257 return 0;
258 }
259
bt_goep_transport_rfcomm_connect(struct bt_conn * conn,struct bt_goep * goep,uint8_t channel)260 int bt_goep_transport_rfcomm_connect(struct bt_conn *conn, struct bt_goep *goep, uint8_t channel)
261 {
262 int err;
263 uint32_t mtu;
264 uint32_t hdr_size;
265
266 if (!conn || !goep || !goep->transport_ops || !goep->obex.client_ops ||
267 !goep->obex.client_ops->connect || !goep->obex.client_ops->disconnect) {
268 LOG_DBG("Invalid parameter");
269 return -EINVAL;
270 }
271
272 hdr_size = sizeof(struct bt_l2cap_hdr);
273 hdr_size += BT_RFCOMM_HDR_SIZE + BT_RFCOMM_FCS_SIZE;
274
275 mtu = CONFIG_BT_GOEP_RFCOMM_MTU - hdr_size;
276 /* Use default MTU if it is not given */
277 if (!goep->obex.rx.mtu) {
278 goep->obex.rx.mtu = mtu;
279 }
280
281 if (goep->obex.rx.mtu < GOEP_MIN_MTU) {
282 LOG_WRN("GOEP RFCOMM MTU less than minimum size (%d < %d)", goep->obex.rx.mtu,
283 GOEP_MIN_MTU);
284 goep->obex.rx.mtu = GOEP_MIN_MTU;
285 }
286
287 if (goep->obex.rx.mtu > mtu) {
288 LOG_WRN("GOEP RFCOMM MTU exceeds maximum size (%d > %d)", goep->obex.rx.mtu, mtu);
289 goep->obex.rx.mtu = mtu;
290 }
291
292 err = bt_obex_reg_transport(&goep->obex, &goep_rfcomm_transport_ops);
293 if (err) {
294 LOG_WRN("Fail to reg transport ops");
295 return err;
296 }
297
298 goep->_goep_v2 = false;
299 goep->_acl = conn;
300 goep->_transport.dlc.mtu = goep->obex.rx.mtu;
301 goep->_transport.dlc.ops = &goep_rfcomm_ops;
302 goep->_transport.dlc.required_sec_level = BT_SECURITY_L2;
303
304 err = bt_rfcomm_dlc_connect(conn, &goep->_transport.dlc, channel);
305 if (err) {
306 LOG_WRN("Fail to create RFCOMM connection");
307 return err;
308 }
309
310 atomic_set(&goep->_state, BT_GOEP_TRANSPORT_CONNECTING);
311
312 return 0;
313 }
314
bt_goep_transport_rfcomm_disconnect(struct bt_goep * goep)315 int bt_goep_transport_rfcomm_disconnect(struct bt_goep *goep)
316 {
317 int err;
318 uint32_t state;
319
320 if (!goep || goep->_goep_v2) {
321 LOG_DBG("Invalid parameter");
322 return -EINVAL;
323 }
324
325 state = atomic_get(&goep->_state);
326 if (state != BT_GOEP_TRANSPORT_CONNECTED) {
327 LOG_DBG("Invalid stats %d", state);
328 return -ENOTCONN;
329 }
330
331 err = bt_rfcomm_dlc_disconnect(&goep->_transport.dlc);
332 if (err) {
333 LOG_WRN("Fail to disconnect RFCOMM DLC");
334 return err;
335 }
336
337 atomic_set(&goep->_state, BT_GOEP_TRANSPORT_DISCONNECTING);
338
339 return 0;
340 }
341
342 /* L2CAP Server list */
343 static sys_slist_t goep_l2cap_server = SYS_SLIST_STATIC_INIT(&goep_l2cap_server);
344
goep_l2cap_recv(struct bt_l2cap_chan * chan,struct net_buf * buf)345 static int goep_l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
346 {
347 struct bt_goep *goep = CONTAINER_OF(chan, struct bt_goep, _transport.chan.chan);
348 int err;
349
350 err = bt_obex_recv(&goep->obex, buf);
351 if (err) {
352 LOG_WRN("Fail to handle OBEX packet (err %d)", err);
353 }
354 return err;
355 }
356
goep_l2cap_connected(struct bt_l2cap_chan * chan)357 static void goep_l2cap_connected(struct bt_l2cap_chan *chan)
358 {
359 struct bt_goep *goep = CONTAINER_OF(chan, struct bt_goep, _transport.chan.chan);
360 int err;
361
362 LOG_DBG("L2CAP channel %p connected", chan);
363
364 if ((goep->_transport.chan.tx.mtu < GOEP_MIN_MTU) ||
365 (goep->_transport.chan.rx.mtu < GOEP_MIN_MTU)) {
366 LOG_WRN("Invalid MTU (local %d, peer %d", goep->_transport.chan.rx.mtu,
367 goep->_transport.chan.tx.mtu);
368 bt_l2cap_chan_disconnect(chan);
369 return;
370 }
371
372 goep->obex.rx.mtu = goep->_transport.chan.rx.mtu;
373 goep->obex.tx.mtu = goep->_transport.chan.tx.mtu;
374
375 /* Set MOPL of RX to MTU by default */
376 goep->obex.rx.mopl = goep->_transport.chan.rx.mtu;
377 /* Set MOPL of TX to MTU by default to avoid the OBEX connect req cannot be sent. */
378 goep->obex.tx.mopl = goep->_transport.chan.tx.mtu;
379
380 atomic_set(&goep->_state, BT_GOEP_TRANSPORT_CONNECTED);
381
382 err = bt_obex_transport_connected(&goep->obex);
383 if (err) {
384 LOG_WRN("Notify OBEX (err %d). Disconnecting transport...", err);
385 bt_l2cap_chan_disconnect(chan);
386 return;
387 }
388
389 if (goep->transport_ops->connected) {
390 goep->transport_ops->connected(goep->_acl, goep);
391 }
392 }
393
goep_l2cap_disconnected(struct bt_l2cap_chan * chan)394 static void goep_l2cap_disconnected(struct bt_l2cap_chan *chan)
395 {
396 struct bt_goep *goep = CONTAINER_OF(chan, struct bt_goep, _transport.chan.chan);
397 int err;
398
399 LOG_DBG("L2CAP channel %p disconnected", chan);
400
401 atomic_set(&goep->_state, BT_GOEP_TRANSPORT_DISCONNECTED);
402
403 err = bt_obex_transport_disconnected(&goep->obex);
404 if (err) {
405 LOG_WRN("Notify OBEX (err %d).", err);
406 }
407
408 if (goep->transport_ops->disconnected) {
409 goep->transport_ops->disconnected(goep);
410 }
411 }
412
413 static const struct bt_l2cap_chan_ops goep_l2cap_ops = {
414 .recv = goep_l2cap_recv,
415 .connected = goep_l2cap_connected,
416 .disconnected = goep_l2cap_disconnected,
417 };
418
goep_l2cap_send(struct bt_obex * obex,struct net_buf * buf)419 static int goep_l2cap_send(struct bt_obex *obex, struct net_buf *buf)
420 {
421 struct bt_goep *goep = CONTAINER_OF(obex, struct bt_goep, obex);
422
423 if (!goep->_goep_v2) {
424 LOG_WRN("Invalid transport");
425 return -EINVAL;
426 }
427
428 if (buf->len > obex->tx.mtu) {
429 LOG_WRN("Packet size exceeds MTU");
430 return -EMSGSIZE;
431 }
432
433 return bt_l2cap_chan_send(&goep->_transport.chan.chan, buf);
434 }
435
goep_l2cap_alloc_buf(struct bt_obex * obex,struct net_buf_pool * pool)436 static struct net_buf *goep_l2cap_alloc_buf(struct bt_obex *obex, struct net_buf_pool *pool)
437 {
438 struct bt_goep *goep = CONTAINER_OF(obex, struct bt_goep, obex);
439
440 if (!goep->_goep_v2) {
441 LOG_WRN("Invalid transport");
442 return NULL;
443 }
444
445 return bt_goep_create_pdu(goep, pool);
446 }
447
goep_l2cap_disconnect(struct bt_obex * obex)448 static int goep_l2cap_disconnect(struct bt_obex *obex)
449 {
450 struct bt_goep *goep = CONTAINER_OF(obex, struct bt_goep, obex);
451
452 if (!goep->_goep_v2) {
453 LOG_WRN("Invalid transport");
454 return -EINVAL;
455 }
456
457 return bt_l2cap_chan_disconnect(&goep->_transport.chan.chan);
458 }
459
460 static const struct bt_obex_transport_ops goep_l2cap_transport_ops = {
461 .alloc_buf = goep_l2cap_alloc_buf,
462 .send = goep_l2cap_send,
463 .disconnect = goep_l2cap_disconnect,
464 };
465
goep_l2cap_accept(struct bt_conn * conn,struct bt_l2cap_server * server,struct bt_l2cap_chan ** chan)466 static int goep_l2cap_accept(struct bt_conn *conn, struct bt_l2cap_server *server,
467 struct bt_l2cap_chan **chan)
468 {
469 struct bt_goep_transport_l2cap_server *l2cap_server;
470 struct bt_goep *goep;
471 uint32_t mtu;
472 uint32_t hdr_size;
473 int err;
474
475 l2cap_server = CONTAINER_OF(server, struct bt_goep_transport_l2cap_server, l2cap);
476
477 if (!sys_slist_find(&goep_l2cap_server, &l2cap_server->node, NULL)) {
478 LOG_WRN("Invalid l2cap server");
479 return -ENOMEM;
480 }
481
482 err = l2cap_server->accept(conn, l2cap_server, &goep);
483 if (err) {
484 LOG_DBG("Incoming connection rejected");
485 return err;
486 }
487
488 if (!goep || !goep->transport_ops || !goep->obex.server_ops ||
489 !goep->obex.server_ops->connect || !goep->obex.server_ops->disconnect) {
490 LOG_DBG("Invalid parameter");
491 return -EINVAL;
492 }
493
494 hdr_size = sizeof(struct bt_l2cap_hdr);
495
496 mtu = CONFIG_BT_GOEP_L2CAP_MTU - hdr_size;
497 /* Use default MTU if it is not given */
498 if (!goep->obex.rx.mtu) {
499 goep->obex.rx.mtu = mtu;
500 }
501
502 if (goep->obex.rx.mtu < GOEP_MIN_MTU) {
503 LOG_WRN("GOEP RFCOMM MTU less than minimum size (%d < %d)", goep->obex.rx.mtu,
504 GOEP_MIN_MTU);
505 goep->obex.rx.mtu = GOEP_MIN_MTU;
506 }
507
508 if (goep->obex.rx.mtu > mtu) {
509 LOG_WRN("GOEP RFCOMM MTU exceeds maximum size (%d > %d)", goep->obex.rx.mtu, mtu);
510 goep->obex.rx.mtu = mtu;
511 }
512
513 err = bt_obex_reg_transport(&goep->obex, &goep_l2cap_transport_ops);
514 if (err) {
515 LOG_WRN("Fail to reg transport ops");
516 return err;
517 }
518
519 goep->_goep_v2 = true;
520 goep->_acl = conn;
521 *chan = &goep->_transport.chan.chan;
522 goep->_transport.chan.rx.mode = BT_L2CAP_BR_LINK_MODE_ERET;
523 goep->_transport.chan.rx.optional = false;
524 goep->_transport.chan.rx.max_transmit = 3;
525 goep->_transport.chan.rx.mtu = goep->obex.rx.mtu;
526 goep->_transport.chan.rx.extended_control = false;
527 goep->_transport.chan.chan.ops = &goep_l2cap_ops;
528 goep->_transport.chan.required_sec_level = BT_SECURITY_L2;
529
530 atomic_set(&goep->_state, BT_GOEP_TRANSPORT_CONNECTING);
531
532 return 0;
533 }
534
bt_goep_transport_l2cap_server_register(struct bt_goep_transport_l2cap_server * server)535 int bt_goep_transport_l2cap_server_register(struct bt_goep_transport_l2cap_server *server)
536 {
537 int err;
538
539 if (!server || !server->accept) {
540 LOG_DBG("Invalid parameter");
541 return -EINVAL;
542 }
543
544 if (sys_slist_find(&goep_l2cap_server, &server->node, NULL)) {
545 LOG_WRN("L2CAP server has been registered");
546 return -EEXIST;
547 }
548
549 server->l2cap.accept = goep_l2cap_accept;
550 err = bt_l2cap_br_server_register(&server->l2cap);
551 if (err) {
552 LOG_WRN("Fail to register L2CAP Server %p", server);
553 return err;
554 }
555
556 LOG_DBG("Register L2CAP server %p", server);
557 sys_slist_append(&goep_l2cap_server, &server->node);
558
559 return 0;
560 }
561
bt_goep_transport_l2cap_connect(struct bt_conn * conn,struct bt_goep * goep,uint16_t psm)562 int bt_goep_transport_l2cap_connect(struct bt_conn *conn, struct bt_goep *goep, uint16_t psm)
563 {
564 int err;
565 uint32_t state;
566 uint32_t mtu;
567 uint32_t hdr_size;
568
569 if (!conn || !goep || !goep->transport_ops || !goep->obex.client_ops ||
570 !goep->obex.client_ops->connect || !goep->obex.client_ops->disconnect) {
571 LOG_DBG("Invalid parameter");
572 return -EINVAL;
573 }
574
575 state = atomic_get(&goep->_state);
576 if (state != BT_GOEP_TRANSPORT_DISCONNECTED) {
577 LOG_DBG("Invalid stats %d", state);
578 return -EBUSY;
579 }
580
581 hdr_size = sizeof(struct bt_l2cap_hdr);
582
583 mtu = CONFIG_BT_GOEP_L2CAP_MTU - hdr_size;
584 /* Use default MTU if it is not given */
585 if (!goep->obex.rx.mtu) {
586 goep->obex.rx.mtu = mtu;
587 }
588
589 if (goep->obex.rx.mtu < GOEP_MIN_MTU) {
590 LOG_WRN("GOEP RFCOMM MTU less than minimum size (%d < %d)", goep->obex.rx.mtu,
591 GOEP_MIN_MTU);
592 goep->obex.rx.mtu = GOEP_MIN_MTU;
593 }
594
595 if (goep->obex.rx.mtu > mtu) {
596 LOG_WRN("GOEP RFCOMM MTU exceeds maximum size (%d > %d)", goep->obex.rx.mtu, mtu);
597 goep->obex.rx.mtu = mtu;
598 }
599
600 err = bt_obex_reg_transport(&goep->obex, &goep_l2cap_transport_ops);
601 if (err) {
602 LOG_WRN("Fail to reg transport ops");
603 return err;
604 }
605
606 goep->_goep_v2 = true;
607 goep->_acl = conn;
608 goep->_transport.chan.rx.mode = BT_L2CAP_BR_LINK_MODE_ERET;
609 goep->_transport.chan.rx.optional = false;
610 goep->_transport.chan.rx.max_transmit = 3;
611 goep->_transport.chan.rx.mtu = goep->obex.rx.mtu;
612 goep->_transport.chan.rx.extended_control = false;
613 goep->_transport.chan.chan.ops = &goep_l2cap_ops;
614 goep->_transport.chan.required_sec_level = BT_SECURITY_L2;
615
616 err = bt_l2cap_chan_connect(conn, &goep->_transport.chan.chan, psm);
617 if (err) {
618 LOG_WRN("Fail to create L2CAP connection");
619 return err;
620 }
621
622 atomic_set(&goep->_state, BT_GOEP_TRANSPORT_CONNECTING);
623
624 return 0;
625 }
626
bt_goep_transport_l2cap_disconnect(struct bt_goep * goep)627 int bt_goep_transport_l2cap_disconnect(struct bt_goep *goep)
628 {
629 int err;
630 uint32_t state;
631
632 if (!goep || !goep->_goep_v2) {
633 LOG_DBG("Invalid parameter");
634 return -EINVAL;
635 }
636
637 state = atomic_get(&goep->_state);
638 if (state != BT_GOEP_TRANSPORT_CONNECTED) {
639 LOG_DBG("Invalid stats %d", state);
640 return -ENOTCONN;
641 }
642
643 err = bt_l2cap_chan_disconnect(&goep->_transport.chan.chan);
644 if (err) {
645 LOG_WRN("Fail to disconnect L2CAP channel");
646 return err;
647 }
648
649 atomic_set(&goep->_state, BT_GOEP_TRANSPORT_DISCONNECTING);
650
651 return 0;
652 }
653
bt_goep_create_pdu(struct bt_goep * goep,struct net_buf_pool * pool)654 struct net_buf *bt_goep_create_pdu(struct bt_goep *goep, struct net_buf_pool *pool)
655 {
656 struct net_buf *buf;
657 size_t len;
658
659 if (!goep) {
660 LOG_WRN("Invalid parameter");
661 return NULL;
662 }
663
664 if (!goep->_goep_v2) {
665 buf = bt_rfcomm_create_pdu(pool);
666 } else {
667 buf = bt_conn_create_pdu(pool, sizeof(struct bt_l2cap_hdr));
668 }
669
670 if (buf) {
671 len = net_buf_headroom(buf);
672 net_buf_reserve(buf, len + BT_OBEX_SEND_BUF_RESERVE);
673 }
674 return buf;
675 }
676