You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@mynewt.apache.org by Łukasz Rymanowski <lu...@codecoup.pl> on 2017/01/17 13:28:44 UTC

[RFC v2] nimble/l2cap: Add LE L2CAP COC API

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

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
\u0141ukasz
---
 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


Re: [RFC v2] nimble/l2cap: Add LE L2CAP COC API

Posted by Łukasz Rymanowski <lu...@codecoup.pl>.
HI Chris,

On 18 January 2017 at 05:39, Christopher Collins <cc...@apache.org>
wrote:

> Hi Łukasz,
>
> I like it.  I just have one comment:
>
> > > +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);
>
> Is it possible for the user to determine the cause of failure for this
> function?  E.g., resource-exhaustion vs. peer-not-connected?  The rest
> of the host API indicates cause of failure with a BLE_HS_[...] return
> code.  If a function needs to return additional values, it writes them
> to pointer parameters.  Do you think using return codes would make sense
> for this function?
>
>
OK, makes sense. So will change return to int and actually don't need to
pass additional
pointer parameters as user will get *chan in the
BLE_L2CAP_EVENT_COC_CONNECT event.


Thanks,
> Chris
>
>
>
Best
Łukasz

Re: [RFC v2] nimble/l2cap: Add LE L2CAP COC API

Posted by Christopher Collins <cc...@apache.org>.
Hi \u0141ukasz,

I like it.  I just have one comment:

> > +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);

Is it possible for the user to determine the cause of failure for this
function?  E.g., resource-exhaustion vs. peer-not-connected?  The rest
of the host API indicates cause of failure with a BLE_HS_[...] return
code.  If a function needs to return additional values, it writes them
to pointer parameters.  Do you think using return codes would make sense
for this function?

Thanks,
Chris


On Tue, Jan 17, 2017 at 02:41:49PM +0100, \u0141ukasz Rymanowski wrote:
> Hi,
> 
> On 17 January 2017 at 14:28, \u0141ukasz Rymanowski <
> lukasz.rymanowski@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
> > \u0141ukasz
> > ---
> >  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
> \u0141ukasz

Re: [RFC v2] nimble/l2cap: Add LE L2CAP COC API

Posted by Łukasz Rymanowski <lu...@codecoup.pl>.
Hi,

On 17 January 2017 at 14:28, Łukasz Rymanowski <
lukasz.rymanowski@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