Skip to content

Commit 3d91b89

Browse files
lylezhu2012MaureenHelm
authored andcommitted
Bluetooth: GOEP: Enable GOEP feature
Add a Kconfig BT_GOEP to control the GOEP feature. Implement the GOEP protocol and transport, both for GOEP 1.1 and GOEP 2.x. For GOEP transport, OBEX over RFCOMM, and OBEX over L2CAP are supported. For GOEP protocol, `put`, `get`, `abort`, `setpath`, and `action` are supported. And only one operation can be processed at the same time. The feature `Reliable Session` is unsupported. Signed-off-by: Lyle Zhu <[email protected]>
1 parent c4af18d commit 3d91b89

File tree

8 files changed

+5857
-0
lines changed

8 files changed

+5857
-0
lines changed
Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
/* goep.h - Bluetooth Generic Object Exchange Profile handling */
2+
3+
/*
4+
* Copyright 2024-2025 NXP
5+
*
6+
* SPDX-License-Identifier: Apache-2.0
7+
*/
8+
9+
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_GOEP_H_
10+
#define ZEPHYR_INCLUDE_BLUETOOTH_GOEP_H_
11+
12+
/**
13+
* @brief Generic Object Exchange Profile (GOEP)
14+
* @defgroup bt_goep Generic Object Exchange Profile (GOEP)
15+
* @ingroup bluetooth
16+
* @{
17+
*/
18+
19+
#include <zephyr/kernel.h>
20+
#include <string.h>
21+
#include <errno.h>
22+
#include <stdbool.h>
23+
24+
#include <zephyr/bluetooth/bluetooth.h>
25+
#include <zephyr/bluetooth/conn.h>
26+
#include <zephyr/bluetooth/l2cap.h>
27+
#include <zephyr/bluetooth/classic/rfcomm.h>
28+
#include <zephyr/bluetooth/classic/obex.h>
29+
30+
#ifdef __cplusplus
31+
extern "C" {
32+
#endif
33+
34+
struct bt_goep;
35+
36+
/** @brief GOEP transport operations structure.
37+
*
38+
* The object has to stay valid and constant for the lifetime of the GOEP server and client.
39+
*/
40+
struct bt_goep_transport_ops {
41+
/** @brief GOEP transport connected callback
42+
*
43+
* If this callback is provided it will be called whenever the GOEP transport connection
44+
* completes.
45+
*
46+
* @param conn The ACL connection.
47+
* @param goep The GOEP object that has been connected.
48+
*/
49+
void (*connected)(struct bt_conn *conn, struct bt_goep *goep);
50+
51+
/** @brief GOEP transport disconnected callback
52+
*
53+
* If this callback is provided it will be called whenever the GOEP transport is
54+
* disconnected, including when a connection gets rejected.
55+
*
56+
* @param goep The GOEP object that has been disconnected.
57+
*/
58+
void (*disconnected)(struct bt_goep *goep);
59+
};
60+
61+
/** @brief Life-span states of GOEP transport.
62+
*
63+
* Used only by internal APIs dealing with setting GOEP to proper transport state depending on
64+
* operational context.
65+
*
66+
* GOEP transport enters the @ref BT_GOEP_TRANSPORT_CONNECTING state upon
67+
* @ref bt_goep_transport_l2cap_connect, @ref bt_goep_transport_rfcomm_connect or upon returning
68+
* from @ref bt_goep_transport_rfcomm_server::accept and bt_goep_transport_l2cap_server::accept.
69+
*
70+
* When GOEP transport leaves the @ref BT_GOEP_TRANSPORT_CONNECTING state and enters the @ref
71+
* BT_GOEP_TRANSPORT_CONNECTED, @ref bt_goep_transport_ops::connected is called.
72+
*
73+
* When GOEP transport enters the @ref BT_GOEP_TRANSPORT_DISCONNECTED from other states,
74+
* @ref bt_goep_transport_ops::disconnected is called.
75+
*/
76+
enum __packed bt_goep_transport_state {
77+
/** GOEP disconnected */
78+
BT_GOEP_TRANSPORT_DISCONNECTED,
79+
/** GOEP in connecting state */
80+
BT_GOEP_TRANSPORT_CONNECTING,
81+
/** GOEP ready for upper layer traffic on it */
82+
BT_GOEP_TRANSPORT_CONNECTED,
83+
/** GOEP in disconnecting state */
84+
BT_GOEP_TRANSPORT_DISCONNECTING,
85+
};
86+
87+
struct bt_goep {
88+
/** @internal To be used for transport */
89+
union {
90+
struct bt_rfcomm_dlc dlc;
91+
struct bt_l2cap_br_chan chan;
92+
} _transport;
93+
94+
/** @internal Peer GOEP Version
95+
*
96+
* false - Peer supports GOEP v1.1. The GOEP transport is based on RFCOMM.
97+
* `dlc` is used as transport.
98+
*
99+
* true - peer supports GOEP v2.0 or later. The GOEP transport is based on L2CAP.
100+
* `chan` is used as transport.
101+
*/
102+
bool _goep_v2;
103+
104+
/** @internal connection handle */
105+
struct bt_conn *_acl;
106+
107+
/** @internal Saves the current transport state, @ref bt_goep_transport_state */
108+
atomic_t _state;
109+
110+
/** @brief GOEP transport operations
111+
*
112+
* The upper layer should pass the operations to `transport_ops` when
113+
* providing the GOEP structure.
114+
*/
115+
const struct bt_goep_transport_ops *transport_ops;
116+
117+
/** @brief OBEX object */
118+
struct bt_obex obex;
119+
};
120+
121+
/**
122+
* @defgroup bt_goep_transport_rfcomm GOEP transport RFCOMM
123+
* @ingroup bt_goep
124+
* @{
125+
*/
126+
127+
/** @brief GOEP Server structure GOEP v1.1. */
128+
struct bt_goep_transport_rfcomm_server {
129+
/** @brief RFCOMM server for GOEP v1.1
130+
*
131+
* The @ref bt_goep_transport_rfcomm_server::rfcomm is used to register a rfcomm server.
132+
*
133+
* The @ref bt_rfcomm_server::channel needs to be passed with a pre-set channel (not
134+
* recommended however), Or give a value `0` to make the channel be auto-allocated when
135+
* @ref bt_goep_transport_rfcomm_server_register is called.
136+
* The @ref bt_rfcomm_server::accept should be not used by GOEP application, and instead
137+
* the @ref bt_goep_transport_rfcomm_server::accept should be used.
138+
*/
139+
struct bt_rfcomm_server rfcomm;
140+
141+
/** @brief Server accept callback
142+
*
143+
* This callback is called whenever a new incoming GOEP connection requires
144+
* authorization.
145+
*
146+
* @warning It is the responsibility of the caller to zero out the parent of the GOEP
147+
* object.
148+
*
149+
* @param conn The connection that is requesting authorization.
150+
* @param server Pointer to the server structure this callback relates to.
151+
* @param goep Pointer to received the allocated GOEP object.
152+
*
153+
* @return 0 in case of success or negative value in case of error.
154+
* @return -ENOMEM if no available space for new object.
155+
* @return -EACCES if application did not authorize the connection.
156+
* @return -EPERM if encryption key size is too short.
157+
*/
158+
int (*accept)(struct bt_conn *conn, struct bt_goep_transport_rfcomm_server *server,
159+
struct bt_goep **goep);
160+
161+
sys_snode_t node;
162+
};
163+
164+
/** @brief Register GOEP RFCOMM server.
165+
*
166+
* Register GOEP server for a RFCOMM channel @ref bt_rfcomm_server::channel, each new connection
167+
* is authorized using the @ref bt_goep_transport_rfcomm_server::accept callback which in case of
168+
* success shall allocate the GOEP structure @ref bt_goep to be used by the new GOEP connection.
169+
*
170+
* @ref bt_rfcomm_server::channel may be pre-set to a given value (not recommended however). Or be
171+
* left as 0, in which case the channel will be auto-allocated by RFCOMM.
172+
*
173+
* @param server Server structure.
174+
*
175+
* @return 0 in case of success or negative value in case of error.
176+
*/
177+
int bt_goep_transport_rfcomm_server_register(struct bt_goep_transport_rfcomm_server *server);
178+
179+
/** @brief Connect GOEP transport over RFCOMM
180+
*
181+
* Connect GOEP transport over RFCOMM, once the connection is completed, the callback
182+
* @ref bt_goep_transport_ops::connected is called. If the connection is rejected,
183+
* @ref bt_goep_transport_ops::disconnected callback is called instead.
184+
* The GOEP object is passed (over an address of it) as second parameter, application should
185+
* create transport dedicated GOEP object @ref bt_goep. Then pass to this API the location
186+
* (address).
187+
* Before calling the API, @ref bt_obex::client_ops and @ref bt_goep::transport_ops should
188+
* be initialized with valid address of type @ref bt_obex_client_ops object and
189+
* @ref bt_goep_transport_ops object. The field `mtu` of @ref bt_obex::rx could be passed with
190+
* valid value. Or set it to zero, the mtu will be calculated according to
191+
* @kconfig{CONFIG_BT_GOEP_RFCOMM_MTU}.
192+
* The RFCOMM channel is passed as third parameter. It is the RFCOMM channel of RFCOMM server of
193+
* peer device.
194+
*
195+
* @warning It is the responsibility of the caller to zero out the parent of the GOEP object.
196+
*
197+
* @param conn Connection object.
198+
* @param goep GOEP object.
199+
* @param channel RFCOMM channel to connect to.
200+
*
201+
* @return 0 in case of success or negative value in case of error.
202+
*/
203+
int bt_goep_transport_rfcomm_connect(struct bt_conn *conn, struct bt_goep *goep, uint8_t channel);
204+
205+
/** @brief Disconnect GOEP transport from RFCOMM
206+
*
207+
* Disconnect GOEP RFCOMM transport.
208+
*
209+
* @param goep GOEP object.
210+
*
211+
* @return 0 in case of success or negative value in case of error.
212+
*/
213+
int bt_goep_transport_rfcomm_disconnect(struct bt_goep *goep);
214+
215+
/** @} */
216+
217+
/**
218+
* @defgroup bt_goep_transport_l2cap GOEP transport L2CAP
219+
* @ingroup bt_goep
220+
* @{
221+
*/
222+
223+
/** @brief GOEP Server structure for GOEP v2.0 and later. */
224+
struct bt_goep_transport_l2cap_server {
225+
/** @brief L2CAP PSM for GOEP v2.0 and later
226+
*
227+
* The @ref bt_goep_transport_l2cap_server::l2cap is used to register a l2cap server.
228+
*
229+
* The @ref bt_l2cap_server::psm needs to be passed with a pre-set psm (not recommended
230+
* however), Or give a value `0` to make the psm be auto-allocated when
231+
* @ref bt_goep_transport_l2cap_server_register is called.
232+
* The @ref bt_l2cap_server::sec_level is used to require minimum security level for l2cap
233+
* server.
234+
* The @ref bt_l2cap_server::accept should be not used by GOEP application, and instead
235+
* the @ref bt_goep_transport_l2cap_server::accept will be used.
236+
*/
237+
struct bt_l2cap_server l2cap;
238+
239+
/** @brief Server accept callback
240+
*
241+
* This callback is called whenever a new incoming GOEP connection requires
242+
* authorization.
243+
*
244+
* @warning It is the responsibility of the caller to zero out the parent of the GOEP
245+
* object.
246+
*
247+
* @param conn The connection that is requesting authorization.
248+
* @param server Pointer to the server structure this callback relates to.
249+
* @param goep Pointer to received the allocated GOEP object.
250+
*
251+
* @return 0 in case of success or negative value in case of error.
252+
* @return -ENOMEM if no available space for new object.
253+
* @return -EACCES if application did not authorize the connection.
254+
* @return -EPERM if encryption key size is too short.
255+
*/
256+
int (*accept)(struct bt_conn *conn, struct bt_goep_transport_l2cap_server *server,
257+
struct bt_goep **goep);
258+
259+
sys_snode_t node;
260+
};
261+
262+
/** @brief Register GOEP L2CAP server.
263+
*
264+
* Register GOEP server for a L2CAP PSM @ref bt_l2cap_server::psm. each new connection is
265+
* authorized using the @ref bt_goep_transport_l2cap_server::accept callback which in case of
266+
* success shall allocate the GOEP structure @ref bt_goep to be used by the new GOEP connection.
267+
*
268+
* For L2CAP PSM, for fixed, SIG-assigned PSMs (in the range 0x0001-0x0eff) the PSM should not be
269+
* used. For dynamic PSMs (in the range 0x1000-0xffff),
270+
* @ref bt_l2cap_server::psm may be pre-set to a given value (not recommended however). And it
271+
* shall have the least significant bit of the most significant octet equal to 0 and the least
272+
* significant bit of all other octets equal to 1. Or be left as 0, in which case the channel
273+
* will be auto-allocated by L2CAP.
274+
*
275+
* @param server Server structure.
276+
*
277+
* @return 0 in case of success or negative value in case of error.
278+
*/
279+
int bt_goep_transport_l2cap_server_register(struct bt_goep_transport_l2cap_server *server);
280+
281+
/** @brief Connect GOEP transport over L2CAP
282+
*
283+
* Connect GOEP transport by L2CAP, once the connection is completed, the callback
284+
* @ref bt_goep_transport_ops::connected is called. If the connection is rejected,
285+
* @ref bt_goep_transport_ops::disconnected callback is called instead.
286+
* The GOEP object is passed (over an address of it) as second parameter, application should
287+
* create transport dedicated GOEP object @ref bt_goep. Then pass to this API the location
288+
* (address).
289+
* Before calling the API, @ref bt_obex::client_ops and @ref bt_goep::transport_ops should
290+
* be initialized with valid address of type @ref bt_obex_client_ops object and
291+
* @ref bt_goep_transport_ops object. The field `mtu` of @ref bt_obex::rx could be passed with
292+
* valid value. Or set it to zero, the mtu will be calculated according to
293+
* @kconfig{CONFIG_BT_GOEP_L2CAP_MTU}.
294+
* The L2CAP PSM is passed as third parameter. It is the RFCOMM channel of RFCOMM server of peer
295+
* device.
296+
*
297+
* @warning It is the responsibility of the caller to zero out the parent of the GOEP object.
298+
*
299+
* @param conn Connection object.
300+
* @param goep GOEP object.
301+
* @param psm L2CAP PSM to connect to.
302+
*
303+
* @return 0 in case of success or negative value in case of error.
304+
*/
305+
int bt_goep_transport_l2cap_connect(struct bt_conn *conn, struct bt_goep *goep, uint16_t psm);
306+
307+
/** @brief Disconnect GOEP transport from L2CAP channel
308+
*
309+
* Disconnect GOEP L2CAP transport.
310+
*
311+
* @param goep GOEP object.
312+
*
313+
* @return 0 in case of success or negative value in case of error.
314+
*/
315+
int bt_goep_transport_l2cap_disconnect(struct bt_goep *goep);
316+
317+
/** @} */
318+
319+
/** @brief Allocate the buffer from given pool after reserving head room for GOEP
320+
*
321+
* For GOEP connection over RFCOMM, the reserved head room includes OBEX, RFCOMM, L2CAP and ACL
322+
* headers.
323+
* For GOEP connection over L2CAP, the reserved head room includes OBEX, L2CAP and ACL headers.
324+
*
325+
* @param goep GOEP object.
326+
* @param pool Which pool to take the buffer from.
327+
*
328+
* @return New buffer.
329+
*/
330+
struct net_buf *bt_goep_create_pdu(struct bt_goep *goep, struct net_buf_pool *pool);
331+
332+
#ifdef __cplusplus
333+
}
334+
#endif
335+
336+
/**
337+
* @}
338+
*/
339+
340+
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_GOEP_H_ */

0 commit comments

Comments
 (0)