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