This is an automated email from the ASF dual-hosted git repository.

janc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git

commit 925e781ee4410af791aa9a4219d0da2e41668657
Author: Szymon Janc <[email protected]>
AuthorDate: Wed Dec 10 15:39:30 2025 +0100

    nimble/host: Add function to remove L2CAP CoC server
    
    This allows application to remove previously registered L2CAP CoC
    server.
---
 nimble/host/include/host/ble_l2cap.h  | 13 +++++++
 nimble/host/src/ble_l2cap.c           | 20 +++++++++-
 nimble/host/src/ble_l2cap_coc.c       | 69 +++++++++++++++++++----------------
 nimble/host/src/ble_l2cap_coc_priv.h  | 16 ++++++--
 nimble/host/test/src/ble_l2cap_test.c | 24 ++++++++++++
 5 files changed, 105 insertions(+), 37 deletions(-)

diff --git a/nimble/host/include/host/ble_l2cap.h 
b/nimble/host/include/host/ble_l2cap.h
index 32bd41bc8..65329b87a 100644
--- a/nimble/host/include/host/ble_l2cap.h
+++ b/nimble/host/include/host/ble_l2cap.h
@@ -546,6 +546,19 @@ uint16_t ble_l2cap_get_conn_handle(struct ble_l2cap_chan 
*chan);
 int ble_l2cap_create_server(uint16_t psm, uint16_t mtu,
                             ble_l2cap_event_fn *cb, void *cb_arg);
 
+/**
+ * @brief Removes an L2CAP server.
+ *
+ * This function removes an L2CAP server with the specified Protocol/Service
+ * Multiplexer (PSM). Existing connections for this PSM are not removed.
+ *
+ * @param psm       The Protocol/Service Multiplexer (PSM) for the server.
+ *
+ * @return          0 on success;
+ *                  A non-zero value on failure.
+ */
+int ble_l2cap_remove_server(uint16_t psm);
+
 /**
  * @brief Initiate an L2CAP connection.
  *
diff --git a/nimble/host/src/ble_l2cap.c b/nimble/host/src/ble_l2cap.c
index c79081eec..0d1b4ebc9 100644
--- a/nimble/host/src/ble_l2cap.c
+++ b/nimble/host/src/ble_l2cap.c
@@ -145,7 +145,25 @@ int
 ble_l2cap_create_server(uint16_t psm, uint16_t mtu,
                         ble_l2cap_event_fn *cb, void *cb_arg)
 {
-    return ble_l2cap_coc_create_server(psm, mtu, cb, cb_arg);
+    int rc;
+
+    ble_hs_lock();
+    rc = ble_l2cap_coc_create_server_nolock(psm, mtu, cb, cb_arg);
+    ble_hs_unlock();
+
+    return rc;
+}
+
+int
+ble_l2cap_remove_server(uint16_t psm)
+{
+    int rc;
+
+    ble_hs_lock();
+    rc = ble_l2cap_coc_remove_server_nolock(psm);
+    ble_hs_unlock();
+
+    return rc;
 }
 
 int
diff --git a/nimble/host/src/ble_l2cap_coc.c b/nimble/host/src/ble_l2cap_coc.c
index a63e50770..6ed30a98f 100644
--- a/nimble/host/src/ble_l2cap_coc.c
+++ b/nimble/host/src/ble_l2cap_coc.c
@@ -52,18 +52,6 @@ static os_membuf_t ble_l2cap_coc_srv_mem[
 
 static struct os_mempool ble_l2cap_coc_srv_pool;
 
-static void
-ble_l2cap_coc_dbg_assert_srv_not_inserted(struct ble_l2cap_coc_srv *srv)
-{
-#if MYNEWT_VAL(BLE_HS_DEBUG)
-    struct ble_l2cap_coc_srv *cur;
-
-    STAILQ_FOREACH(cur, &ble_l2cap_coc_srvs, next) {
-        BLE_HS_DBG_ASSERT(cur != srv);
-    }
-#endif
-}
-
 static struct ble_l2cap_coc_srv *
 ble_l2cap_coc_srv_alloc(void)
 {
@@ -77,12 +65,31 @@ ble_l2cap_coc_srv_alloc(void)
     return srv;
 }
 
+static struct ble_l2cap_coc_srv *
+ble_l2cap_coc_srv_find(uint16_t psm)
+{
+    struct ble_l2cap_coc_srv *srv;
+
+    STAILQ_FOREACH(srv, &ble_l2cap_coc_srvs, next) {
+        if (srv->psm == psm) {
+            return srv;
+        }
+    }
+
+    return NULL;
+}
+
 int
-ble_l2cap_coc_create_server(uint16_t psm, uint16_t mtu,
-                            ble_l2cap_event_fn *cb, void *cb_arg)
+ble_l2cap_coc_create_server_nolock(uint16_t psm, uint16_t mtu,
+                                   ble_l2cap_event_fn *cb, void *cb_arg)
 {
     struct ble_l2cap_coc_srv *srv;
 
+    srv = ble_l2cap_coc_srv_find(psm);
+    if (srv) {
+        return BLE_HS_EALREADY;
+    }
+
     srv = ble_l2cap_coc_srv_alloc();
     if (!srv) {
         return BLE_HS_ENOMEM;
@@ -93,13 +100,27 @@ ble_l2cap_coc_create_server(uint16_t psm, uint16_t mtu,
     srv->cb = cb;
     srv->cb_arg = cb_arg;
 
-    ble_l2cap_coc_dbg_assert_srv_not_inserted(srv);
-
     STAILQ_INSERT_HEAD(&ble_l2cap_coc_srvs, srv, next);
 
     return 0;
 }
 
+int
+ble_l2cap_coc_remove_server_nolock(uint16_t psm)
+{
+    struct ble_l2cap_coc_srv *srv;
+
+    srv = ble_l2cap_coc_srv_find(psm);
+    if (!srv) {
+        return BLE_HS_ENOENT;
+    }
+
+    STAILQ_REMOVE(&ble_l2cap_coc_srvs, srv, ble_l2cap_coc_srv, next);
+
+    os_memblock_put(&ble_l2cap_coc_srv_pool, srv);
+    return 0;
+}
+
 static inline void
 ble_l2cap_set_used_cid(uint32_t *cid_mask, int bit)
 {
@@ -152,22 +173,6 @@ ble_l2cap_coc_get_cid(uint32_t *cid_mask)
     return BLE_L2CAP_COC_CID_START + bit;
 }
 
-static struct ble_l2cap_coc_srv *
-ble_l2cap_coc_srv_find(uint16_t psm)
-{
-    struct ble_l2cap_coc_srv *cur, *srv;
-
-    srv = NULL;
-    STAILQ_FOREACH(cur, &ble_l2cap_coc_srvs, next) {
-        if (cur->psm == psm) {
-            srv = cur;
-            break;
-        }
-    }
-
-    return srv;
-}
-
 static void
 ble_l2cap_event_coc_received_data(struct ble_l2cap_chan *chan,
                                   struct os_mbuf *om)
diff --git a/nimble/host/src/ble_l2cap_coc_priv.h 
b/nimble/host/src/ble_l2cap_coc_priv.h
index 8a87303fb..673530324 100644
--- a/nimble/host/src/ble_l2cap_coc_priv.h
+++ b/nimble/host/src/ble_l2cap_coc_priv.h
@@ -58,8 +58,9 @@ struct ble_l2cap_coc_srv {
 
 #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) != 0
 int ble_l2cap_coc_init(void);
-int ble_l2cap_coc_create_server(uint16_t psm, uint16_t mtu,
-                                ble_l2cap_event_fn *cb, void *cb_arg);
+int ble_l2cap_coc_create_server_nolock(uint16_t psm, uint16_t mtu,
+                                       ble_l2cap_event_fn *cb, void *cb_arg);
+int ble_l2cap_coc_remove_server_nolock(uint16_t psm);
 int ble_l2cap_coc_create_srv_chan(struct ble_hs_conn *conn, uint16_t psm,
                                   struct ble_l2cap_chan **chan);
 struct ble_l2cap_chan * ble_l2cap_coc_chan_alloc(struct ble_hs_conn *conn,
@@ -81,8 +82,15 @@ ble_l2cap_coc_init(void) {
 }
 
 static inline int
-ble_l2cap_coc_create_server(uint16_t psm, uint16_t mtu,
-                            ble_l2cap_event_fn *cb, void *cb_arg) {
+ble_l2cap_coc_create_server_nolock(uint16_t psm, uint16_t mtu,
+                                   ble_l2cap_event_fn *cb, void *cb_arg)
+{
+    return BLE_HS_ENOTSUP;
+}
+
+static inline int
+ble_l2cap_coc_remove_server_nolock(uint16_t psm)
+{
     return BLE_HS_ENOTSUP;
 }
 
diff --git a/nimble/host/test/src/ble_l2cap_test.c 
b/nimble/host/test/src/ble_l2cap_test.c
index 5d7729a86..839ac430a 100644
--- a/nimble/host/test/src/ble_l2cap_test.c
+++ b/nimble/host/test/src/ble_l2cap_test.c
@@ -1531,6 +1531,29 @@ TEST_CASE_SELF(ble_l2cap_test_case_sig_coc_conn_multi)
     ble_hs_test_util_assert_mbufs_freed(NULL);
 }
 
+TEST_CASE_SELF(ble_l2cap_test_case_server_create_remove)
+{
+    int rc;
+
+    /* Register server */
+    rc = ble_l2cap_create_server(BLE_L2CAP_TEST_PSM, BLE_L2CAP_TEST_COC_MTU,
+                                 ble_l2cap_test_event, NULL);
+    TEST_ASSERT(rc == 0);
+
+    /* Register second server with same PSM */
+    rc = ble_l2cap_create_server(BLE_L2CAP_TEST_PSM, BLE_L2CAP_TEST_COC_MTU,
+                                 ble_l2cap_test_event, NULL);
+    TEST_ASSERT(rc == BLE_HS_EALREADY);
+
+    /* remove success */
+    rc = ble_l2cap_remove_server(BLE_L2CAP_TEST_PSM);
+    TEST_ASSERT(rc == 0);
+
+    /* second remove shall fail */
+    rc = ble_l2cap_remove_server(BLE_L2CAP_TEST_PSM);
+    TEST_ASSERT(rc == BLE_HS_ENOENT);
+}
+
 TEST_SUITE(ble_l2cap_test_suite)
 {
     ble_l2cap_test_case_bad_header();
@@ -1562,4 +1585,5 @@ TEST_SUITE(ble_l2cap_test_suite)
     ble_l2cap_test_case_coc_send_data_failed_too_big_sdu();
     ble_l2cap_test_case_coc_recv_data_succeed();
     ble_l2cap_test_case_sig_coc_conn_multi();
+    ble_l2cap_test_case_server_create_remove();
 }

Reply via email to