Hi, On 17 January 2017 at 14:28, Łukasz Rymanowski < lukasz.rymanow...@codecoup.pl> wrote:
> This patch adds API for LE Connection Oriented Channels. > Note that implementation is hided behind BLE_L2CAP_COC_MAX_NUM flag > which defines maximum number of supported dynamic channels > > Overview: > Idea is that credits are hidden from the user and controlled by the stack. > User creates its own memory pool for SDU taking into account SDU size and > number > of L2CAP LE COC channels he expect to use. User profiles SDU (os_mbuf) to > the stack when > creates or accepts connection. > > Flow overview. > > Similar to GAP, L2CAP defines following events: > > BLE_L2CAP_COC_EVENT_CONNECT > BLE_L2CAP_COC_EVENT_DISCONNECT > BLE_L2CAP_COC_EVENT_ACCEPT > BLE_L2CAP_COC_EVENT_RECEIVE > > Events shall be as follow: BLE_L2CAP_EVENT_COC_CONNECT BLE_L2CAP_EVENT_COC_DISCONNECT BLE_L2CAP_EVENT_COC_ACCEPT BLE_L2CAP_EVENT_COC_RECEIVE This is something I changed just before sending RFC and forgot to update commit message :) which application should handle in ble_l2cap_event_fn() called cb in > description below. > > Outgoing connection: > 1. *chan = ble_l2cap_connect(conn_handle, psm, mtu, struct os_mbuf *sdu_rx, > *cb, *cb_arg); > > 2. BLE_L2CAP_COC_EVENT_CONNECT event is sent when channel has been > established or rejected. If connection has > been rejected, event contains reason for that. > 3. BLE_L2CAP_COC_EVENT_RECEIVE event is sent on incoming data. Note, it > is sent when SDU is completed > 3a. User needs to call ble_l2cap_recv_ready(*chan, sdu_rx) where sdu_rx is > os_mbuf for next SDU. > 4. To send data do remote device ble_l2cap_send(*chan, sdu_tx) shall be > called > 5. To drop channel ble_l2cap_disconnect(*chan) shall be called. > 6. When disconnected BLE_L2CAP_COC_EVENT_DISCONNECT event is sent > > Incoming connection: > 1. ble_l2cap_create_server(psm, mtu, *cb, *cb_arg) > 2. BLE_L2CAP_COC_EVENT_ACCEPT event is sent on create connection request > if there is server for given PSM in the stack. > 2a. User might want to check required security and MTU requirements before > accepts connection. > 2b. User needs to call ble_l2cap_recv_ready(*chan, sdu_rx) where sdu_rx is > os_mbuf for next SDU. > 2c. If accept_cb returns 0, connection is considered established. > > -- > > Hi all, > > Please have a look on fixed API after Chris comments. > > Best Regards > Łukasz > --- > net/nimble/host/include/host/ble_l2cap.h | 107 > +++++++++++++++++++++++++++++++ > net/nimble/host/src/ble_l2cap.c | 67 ++++++++++++++++++- > net/nimble/host/src/ble_l2cap_priv.h | 21 ++++++ > net/nimble/host/syscfg.yml | 5 ++ > 4 files changed, 197 insertions(+), 3 deletions(-) > > diff --git a/net/nimble/host/include/host/ble_l2cap.h > b/net/nimble/host/include/host/ble_l2cap.h > index 52849af..081c655 100644 > --- a/net/nimble/host/include/host/ble_l2cap.h > +++ b/net/nimble/host/include/host/ble_l2cap.h > @@ -56,6 +56,22 @@ struct ble_hs_conn; > #define BLE_L2CAP_SIG_ERR_MTU_EXCEEDED 0x0001 > #define BLE_L2CAP_SIG_ERR_INVALID_CID 0x0002 > > +#define BLE_L2CAP_COC_ERR_CONNECTION_SUCCESS 0x0000 > +#define BLE_L2CAP_COC_ERR_UNKNOWN_LE_PSM 0x0002 > +#define BLE_L2CAP_COC_ERR_NO_RESOURCES 0x0004 > +#define BLE_L2CAP_COC_ERR_INSUFFICIENT_AUTHEN 0x0005 > +#define BLE_L2CAP_COC_ERR_INSUFFICIENT_AUTHOR 0x0006 > +#define BLE_L2CAP_COC_ERR_INSUFFICIENT_KEY_SZ 0x0007 > +#define BLE_L2CAP_COC_ERR_INSUFFICIENT_ENC 0x0008 > +#define BLE_L2CAP_COC_ERR_INVALID_SOURCE_CID 0x0009 > +#define BLE_L2CAP_COC_ERR_SOURCE_CID_ALREADY_USED 0x000A > +#define BLE_L2CAP_COC_ERR_UNACCEPTABLE_PARAMETERS 0x000B > + > +#define BLE_L2CAP_EVENT_COC_CONNECT 0 > +#define BLE_L2CAP_EVENT_COC_DISCONNECT 1 > +#define BLE_L2CAP_EVENT_COC_ACCEPT 2 > +#define BLE_L2CAP_EVENT_COC_RECEIVE 3 > + > typedef void ble_l2cap_sig_update_fn(uint16_t conn_handle, int status, > void *arg); > > @@ -70,6 +86,97 @@ int ble_l2cap_sig_update(uint16_t conn_handle, > struct ble_l2cap_sig_update_params *params, > ble_l2cap_sig_update_fn *cb, void *cb_arg); > > +struct ble_l2cap_chan; > + > +/** > + * Represents a L2CAP-related event. > + * When such an event occurs, the host notifies the application by > passing an > + * instance of this structure to an application-specified callback. > + */ > +struct ble_l2cap_event { > + /** > + * Indicates the type of L2CAP event that occurred. This is one of > the > + * BLE_L2CAP_EVENT codes. > + */ > + uint8_t type; > + > + /** > + * A discriminated union containing additional details concerning the > L2CAP > + * event. The 'type' field indicates which member of the union is > valid. > + */ > + union { > + /** > + * Represents a connection attempt. Valid for the following event > + * types: > + * o BLE_L2CAP_EVENT_COC_CONNECT */ > + struct { > + /** > + * The status of the connection attempt; > + * o 0: the connection was successfully established. > + * o BLE host error code: the connection attempt failed > for > + * the specified reason. > + */ > + int status; > + > + /** The L2CAP channel of the relevant L2CAP connection. */ > + struct ble_l2cap_chan *chan; > + } connect; > + > + > + /** > + * Represents a terminated connection. Valid for the following > event > + * types: > + * o BLE_L2CAP_EVENT_COC_DISCONNECT > + */ > + struct { > + /** Information about the L2CAP connection prior to > termination. */ > + struct ble_l2cap_chan *chan; > + } disconnect; > + > + /** > + * Represents connection accept. Valid for the following event > + * types: > + * o BLE_L2CAP_EVENT_COC_ACCEPT > + */ > + struct { > + /** Connection handle of the relevant connection */ > + uint16_t conn_handle; > + > + /** MTU supported by peer device on the channel */ > + uint16_t peer_mtu; > + > + /** The L2CAP channel of the relevant L2CAP connection. */ > + struct ble_l2cap_chan *chan; > + } accept; > + > + /** > + * Represents received data. Valid for the following event > + * types: > + * o BLE_L2CAP_EVENT_COC_RECEIVE > + */ > + struct { > + /** The L2CAP channel of the relevant L2CAP connection. */ > + struct ble_l2cap_chan *chan; > + > + /** The mbuf with received SDU. */ > + struct os_mbuf *sdu_rx; > + } receive; > + }; > +}; > + > +typedef int ble_l2cap_event_fn(struct ble_l2cap_event *event, void *arg); > + > +int ble_l2cap_create_server(uint16_t psm, uint16_t mtu, > + ble_l2cap_event_fn *cb, void *cb_arg); > + > +struct ble_l2cap_chan *ble_l2cap_connect(uint16_t conn_handle, uint16_t > psm, > + uint16_t mtu, > + struct os_mbuf *sdu_rx, > + ble_l2cap_event_fn *cb, void > *cb_arg); > +int ble_l2cap_disconnect(struct ble_l2cap_chan *chan); > +int ble_l2cap_send(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_tx); > +void ble_l2cap_recv_ready(struct ble_l2cap_chan *chan, struct os_mbuf > *sdu_rx); > + > #ifdef __cplusplus > } > #endif > diff --git a/net/nimble/host/src/ble_l2cap.c b/net/nimble/host/src/ble_ > l2cap.c > index 7f66b57..db99445 100644 > --- a/net/nimble/host/src/ble_l2cap.c > +++ b/net/nimble/host/src/ble_l2cap.c > @@ -31,8 +31,9 @@ _Static_assert(sizeof (struct ble_l2cap_hdr) == > BLE_L2CAP_HDR_SZ, > struct os_mempool ble_l2cap_chan_pool; > > static os_membuf_t ble_l2cap_chan_mem[ > - OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_L2CAP_MAX_CHANS), > - sizeof (struct ble_l2cap_chan)) > + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_L2CAP_MAX_CHANS) + > + MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM), > + sizeof (struct ble_l2cap_chan)) > ]; > > STATS_SECT_DECL(ble_l2cap_stats) ble_l2cap_stats; > @@ -137,6 +138,64 @@ ble_l2cap_prepend_hdr(struct os_mbuf *om, uint16_t > cid, uint16_t len) > return om; > } > > +int > +ble_l2cap_create_server(uint16_t psm, uint16_t mtu, > + ble_l2cap_event_fn *cb, void *cb_arg) > +{ > +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) == 0 > + return BLE_HS_ENOTSUP; > +#endif > + > + /*TODO: Create server object and put it on the queue */ > + return BLE_HS_ENOTSUP; > +} > + > +struct ble_l2cap_chan * > +ble_l2cap_connect(uint16_t conn_handle, uint16_t psm, uint16_t mtu, > + struct os_mbuf *sdu_rx, ble_l2cap_event_fn *cb, void > *cb_arg) > +{ > +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) == 0 > + return NULL; > +#endif > + > + /* > + * TODO In here we are going to create l2cap channel and send > + * BLE_L2CAP_SIG_OP_CREDIT_CONNECT_REQ > + */ > + return NULL; > +} > + > +int ble_l2cap_disconnect(struct ble_l2cap_chan *chan) > +{ > +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) == 0 > + return BLE_HS_ENOTSUP; > +#endif > + > + /*TODO Implement */ > + return BLE_HS_ENOTSUP; > +} > + > +int > +ble_l2cap_send(struct ble_l2cap_chan *chan, struct os_mbuf *sdu) > +{ > +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) == 0 > + return BLE_HS_ENOTSUP; > +#endif > + > + /*TODO Implement */ > + return BLE_HS_ENOTSUP; > +} > + > +void > +ble_l2cap_recv_ready(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_rx) > +{ > +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) == 0 > + return; > +#endif > + > + /*TODO In here we going to update sdu_rx buffer */ > +} > + > static void > ble_l2cap_forget_rx(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan) > { > @@ -337,7 +396,9 @@ ble_l2cap_init(void) > { > int rc; > > - rc = os_mempool_init(&ble_l2cap_chan_pool, MYNEWT_VAL(BLE_L2CAP_MAX_ > CHANS), > + rc = os_mempool_init(&ble_l2cap_chan_pool, > + MYNEWT_VAL(BLE_L2CAP_MAX_CHANS) + > + MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM), > sizeof (struct ble_l2cap_chan), > ble_l2cap_chan_mem, "ble_l2cap_chan_pool"); > if (rc != 0) { > diff --git a/net/nimble/host/src/ble_l2cap_priv.h > b/net/nimble/host/src/ble_l2cap_priv.h > index 79d58a7..99ee9e9 100644 > --- a/net/nimble/host/src/ble_l2cap_priv.h > +++ b/net/nimble/host/src/ble_l2cap_priv.h > @@ -63,6 +63,22 @@ typedef uint8_t ble_l2cap_chan_flags; > > typedef int ble_l2cap_rx_fn(uint16_t conn_handle, struct os_mbuf **rxom); > > +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) > +struct ble_l2cap_coc_endpoint { > + uint16_t cid; > + uint16_t mtu; > + uint16_t mps; > + uint16_t credits; > + struct os_mbuf *sdu; > +}; > + > +struct ble_l2cap_coc_chan { > + struct ble_l2cap_coc_endpoint rx; > + struct ble_l2cap_coc_endpoint tx; > +}; > + > +#endif > + > struct ble_l2cap_chan { > SLIST_ENTRY(ble_l2cap_chan) blc_next; > uint16_t blc_cid; > @@ -75,6 +91,11 @@ struct ble_l2cap_chan { > uint16_t blc_rx_len; /* Length of current reassembled rx > packet. */ > > ble_l2cap_rx_fn *blc_rx_fn; > + > +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) > + struct ble_l2cap_coc_chan blc_coc; > + struct ble_l2cap_coc_chan_ops *blc_coc_ops; > +#endif > }; > > struct ble_l2cap_hdr { > diff --git a/net/nimble/host/syscfg.yml b/net/nimble/host/syscfg.yml > index a2504bf..62ca6f6 100644 > --- a/net/nimble/host/syscfg.yml > +++ b/net/nimble/host/syscfg.yml > @@ -52,6 +52,11 @@ syscfg.defs: > passes since the previous fragment was received, the > connection is > terminated. A value of 0 means no timeout. > value: 30000 > + BLE_L2CAP_COC_MAX_NUM: > + description: > > + Defines maximum number of LE Connection Oriented Channels > channels. > + When set to (0), LE COC is not compiled in. > + value: 1 > > # Security manager settings. > BLE_SM_LEGACY: > -- > 2.9.3 > > Best Łukasz