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.

Outgoing connection:
1. *chan = ble_l2cap_connect(conn_handle, psm, mtu,
                            ble_l2cap_chan_ops *ops,
                            struct os_mbuf *sdu_rx);

2. ops->connected(*chan) callback is called when channel has been established. 
If connection has
been rejected, ops->disconnected(*chan, coc_err) is called with coc_err which 
contains reason of reject
3. ops->recv(*chan, sdu_rx) callback is called on incoming data. Note, it is 
called 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.

Incoming connection:
1. ble_l2cap_create_server(psm, mtu, *ops, accept_cb)
2. accept_cb(conn_handle, peer_mtu, *chan) is called 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.

Open points:
1. As for now we assume that application is responsible for security on the 
link.
We could consider to move this logic into l2cap but not sure if we want to do so

--

Hi all,

Waiting for comments on proposed API

Best Regards
Łukasz
---
 net/nimble/host/include/host/ble_l2cap.h | 33 ++++++++++++++++
 net/nimble/host/src/ble_l2cap.c          | 68 ++++++++++++++++++++++++++++++--
 net/nimble/host/src/ble_l2cap_priv.h     | 21 ++++++++++
 net/nimble/host/syscfg.yml               |  5 +++
 4 files changed, 124 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..d63f5f2 100644
--- a/net/nimble/host/include/host/ble_l2cap.h
+++ b/net/nimble/host/include/host/ble_l2cap.h
@@ -56,6 +56,17 @@ 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
+
 typedef void ble_l2cap_sig_update_fn(uint16_t conn_handle, int status,
                                      void *arg);
 
@@ -70,6 +81,28 @@ 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;
+
+struct ble_l2cap_chan_ops {
+    void (*connected)(struct ble_l2cap_chan *chan);
+    void (*disconnected)(struct ble_l2cap_chan *chan, uint16_t coc_err);
+    void (*recv)(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_rx);
+};
+
+typedef int ble_l2cap_accept_fn(uint16_t conn_handle, uint16_t peer_mtu,
+                                struct ble_l2cap_chan *chan);
+int ble_l2cap_create_server(uint16_t psm, uint16_t mtu,
+                            struct ble_l2cap_chan_ops *ops,
+                            ble_l2cap_accept_fn *cb);
+
+struct ble_l2cap_chan *ble_l2cap_connect(uint16_t conn_handle, uint16_t psm,
+                                          uint16_t mtu,
+                                          struct ble_l2cap_chan_ops *ops,
+                                          struct os_mbuf *sdu_rx);
+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..654573b 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,65 @@ 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,
+                        struct ble_l2cap_chan_ops *ops,
+                        ble_l2cap_accept_fn *cb)
+{
+#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 ble_l2cap_chan_ops *ops, struct os_mbuf *sdu_rx)
+{
+#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 +397,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

Reply via email to