1 /*
2 * Copyright Runtime.io 2018. All rights reserved.
3 * Copyright (c) 2022 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 /** @file
9 * @brief Bluetooth transport for the mcumgr SMP protocol.
10 */
11
12 #include <zephyr/kernel.h>
13 #include <zephyr/init.h>
14 #include <zephyr/bluetooth/bluetooth.h>
15 #include <zephyr/bluetooth/uuid.h>
16 #include <zephyr/bluetooth/gatt.h>
17 #include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
18 #include <zephyr/mgmt/mcumgr/smp/smp.h>
19 #include <zephyr/mgmt/mcumgr/transport/smp.h>
20 #include <zephyr/mgmt/mcumgr/transport/smp_bt.h>
21 #include <zephyr/mgmt/mcumgr/mgmt/handlers.h>
22 #include <errno.h>
23
24 #include <mgmt/mcumgr/transport/smp_internal.h>
25 #include <mgmt/mcumgr/transport/smp_reassembly.h>
26
27 #include <zephyr/logging/log.h>
28 LOG_MODULE_DECLARE(mcumgr_smp, CONFIG_MCUMGR_TRANSPORT_LOG_LEVEL);
29
30 #define RESTORE_TIME COND_CODE_1(CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL, \
31 (CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL_RESTORE_TIME), \
32 (0))
33 #define RETRY_TIME COND_CODE_1(CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL, \
34 (CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL_RETRY_TIME), \
35 (0))
36
37 #define CONN_PARAM_SMP COND_CODE_1(CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL, \
38 BT_LE_CONN_PARAM( \
39 CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL_MIN_INT, \
40 CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL_MAX_INT, \
41 CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL_LATENCY, \
42 CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL_TIMEOUT), \
43 (NULL))
44 #define CONN_PARAM_PREF COND_CODE_1(CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL, \
45 BT_LE_CONN_PARAM( \
46 CONFIG_BT_PERIPHERAL_PREF_MIN_INT, \
47 CONFIG_BT_PERIPHERAL_PREF_MAX_INT, \
48 CONFIG_BT_PERIPHERAL_PREF_LATENCY, \
49 CONFIG_BT_PERIPHERAL_PREF_TIMEOUT), \
50 (NULL))
51
52 /* Minimum number of bytes that must be able to be sent with a notification to a target device
53 * before giving up
54 */
55 #define SMP_BT_MINIMUM_MTU_SEND_FAILURE 20
56
57 #ifdef CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL
58 /* Verification of SMP Connection Parameters configuration that is not possible in the Kconfig. */
59 BUILD_ASSERT((CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL_TIMEOUT * 4U) >
60 ((1U + CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL_LATENCY) *
61 CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL_MAX_INT));
62 #endif
63
64 struct smp_bt_user_data {
65 struct bt_conn *conn;
66 uint8_t id;
67 };
68
69 /* Verification of user data being able to fit */
70 BUILD_ASSERT(sizeof(struct smp_bt_user_data) <= CONFIG_MCUMGR_TRANSPORT_NETBUF_USER_DATA_SIZE,
71 "CONFIG_MCUMGR_TRANSPORT_NETBUF_USER_DATA_SIZE not large enough to fit Bluetooth"
72 " user data");
73
74 enum {
75 CONN_PARAM_SMP_REQUESTED = BIT(0),
76 };
77
78 struct conn_param_data {
79 struct bt_conn *conn;
80 struct k_work_delayable dwork;
81 struct k_work_delayable ework;
82 uint8_t state;
83 uint8_t id;
84 struct k_sem smp_notify_sem;
85 };
86
87 static uint8_t next_id;
88 static struct smp_transport smp_bt_transport;
89 static struct conn_param_data conn_data[CONFIG_BT_MAX_CONN];
90
91 /* SMP service.
92 * {8D53DC1D-1DB7-4CD3-868B-8A527460AA84}
93 */
94 static struct bt_uuid_128 smp_bt_svc_uuid = BT_UUID_INIT_128(
95 BT_UUID_128_ENCODE(0x8d53dc1d, 0x1db7, 0x4cd3, 0x868b, 0x8a527460aa84));
96
97 /* SMP characteristic; used for both requests and responses.
98 * {DA2E7828-FBCE-4E01-AE9E-261174997C48}
99 */
100 static struct bt_uuid_128 smp_bt_chr_uuid = BT_UUID_INIT_128(
101 BT_UUID_128_ENCODE(0xda2e7828, 0xfbce, 0x4e01, 0xae9e, 0x261174997c48));
102
103 static void connected(struct bt_conn *conn, uint8_t err);
104 static void disconnected(struct bt_conn *conn, uint8_t reason);
105
106 /* Bluetooth connection callback handlers */
107 BT_CONN_CB_DEFINE(mcumgr_bt_callbacks) = {
108 .connected = connected,
109 .disconnected = disconnected,
110 };
111
112 /* Helper function that allocates conn_param_data for a conn. */
conn_param_data_alloc(struct bt_conn * conn)113 static struct conn_param_data *conn_param_data_alloc(struct bt_conn *conn)
114 {
115 for (size_t i = 0; i < ARRAY_SIZE(conn_data); i++) {
116 if (conn_data[i].conn == NULL) {
117 bool valid = false;
118
119 conn_data[i].conn = conn;
120
121 /* Generate an ID for this connection and reset semaphore */
122 while (!valid) {
123 valid = true;
124 conn_data[i].id = next_id;
125 ++next_id;
126
127 if (next_id == 0) {
128 /* Avoid use of 0 (invalid ID) */
129 ++next_id;
130 }
131
132 for (size_t l = 0; l < ARRAY_SIZE(conn_data); l++) {
133 if (l != i && conn_data[l].conn != NULL &&
134 conn_data[l].id == conn_data[i].id) {
135 valid = false;
136 break;
137 }
138 }
139 }
140
141 k_sem_reset(&conn_data[i].smp_notify_sem);
142
143 return &conn_data[i];
144 }
145 }
146
147 /* Conn data must exists. */
148 __ASSERT_NO_MSG(false);
149 return NULL;
150 }
151
152 /* Helper function that returns conn_param_data associated with a conn. */
conn_param_data_get(const struct bt_conn * conn)153 static struct conn_param_data *conn_param_data_get(const struct bt_conn *conn)
154 {
155 for (size_t i = 0; i < ARRAY_SIZE(conn_data); i++) {
156 if (conn_data[i].conn == conn) {
157 return &conn_data[i];
158 }
159 }
160
161 return NULL;
162 }
163
164 /* SMP Bluetooth notification sent callback */
smp_notify_finished(struct bt_conn * conn,void * user_data)165 static void smp_notify_finished(struct bt_conn *conn, void *user_data)
166 {
167 struct conn_param_data *cpd = conn_param_data_get(conn);
168
169 if (cpd != NULL) {
170 k_sem_give(&cpd->smp_notify_sem);
171 }
172 }
173
174 /* Sets connection parameters for a given conn. */
conn_param_set(struct bt_conn * conn,struct bt_le_conn_param * param)175 static void conn_param_set(struct bt_conn *conn, struct bt_le_conn_param *param)
176 {
177 int ret = 0;
178 struct conn_param_data *cpd = conn_param_data_get(conn);
179
180 if (cpd != NULL) {
181 ret = bt_conn_le_param_update(conn, param);
182 if (ret && (ret != -EALREADY)) {
183 /* Try again to avoid being stuck with incorrect connection parameters. */
184 (void)k_work_reschedule(&cpd->ework, K_MSEC(RETRY_TIME));
185 } else {
186 (void)k_work_cancel_delayable(&cpd->ework);
187 }
188 }
189 }
190
191 /* Work handler function for restoring the preferred connection parameters for the connection. */
conn_param_on_pref_restore(struct k_work * work)192 static void conn_param_on_pref_restore(struct k_work *work)
193 {
194 struct conn_param_data *cpd = CONTAINER_OF(work, struct conn_param_data, dwork);
195
196 if (cpd != NULL) {
197 conn_param_set(cpd->conn, CONN_PARAM_PREF);
198 cpd->state &= ~CONN_PARAM_SMP_REQUESTED;
199 }
200 }
201
202 /* Work handler function for retrying on conn negotiation API error. */
conn_param_on_error_retry(struct k_work * work)203 static void conn_param_on_error_retry(struct k_work *work)
204 {
205 struct conn_param_data *cpd = CONTAINER_OF(work, struct conn_param_data, ework);
206 struct bt_le_conn_param *param = (cpd->state & CONN_PARAM_SMP_REQUESTED) ?
207 CONN_PARAM_SMP : CONN_PARAM_PREF;
208
209 conn_param_set(cpd->conn, param);
210 }
211
conn_param_smp_enable(struct bt_conn * conn)212 static void conn_param_smp_enable(struct bt_conn *conn)
213 {
214 struct conn_param_data *cpd = conn_param_data_get(conn);
215
216 if (cpd != NULL) {
217 if (!(cpd->state & CONN_PARAM_SMP_REQUESTED)) {
218 conn_param_set(conn, CONN_PARAM_SMP);
219 cpd->state |= CONN_PARAM_SMP_REQUESTED;
220 }
221
222 /* SMP characteristic in use; refresh the restore timeout. */
223 (void)k_work_reschedule(&cpd->dwork, K_MSEC(RESTORE_TIME));
224 }
225 }
226
227 /**
228 * Write handler for the SMP characteristic; processes an incoming SMP request.
229 */
smp_bt_chr_write(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)230 static ssize_t smp_bt_chr_write(struct bt_conn *conn,
231 const struct bt_gatt_attr *attr,
232 const void *buf, uint16_t len, uint16_t offset,
233 uint8_t flags)
234 {
235 struct conn_param_data *cpd = conn_param_data_get(conn);
236 #ifdef CONFIG_MCUMGR_TRANSPORT_BT_REASSEMBLY
237 int ret;
238 bool started;
239
240 if (cpd == NULL) {
241 LOG_ERR("Null cpd object for connection %p", (void *)conn);
242 return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES);
243 }
244
245 started = (smp_reassembly_expected(&smp_bt_transport) >= 0);
246
247 LOG_DBG("started = %s, buf len = %d", started ? "true" : "false", len);
248 LOG_HEXDUMP_DBG(buf, len, "buf = ");
249
250 ret = smp_reassembly_collect(&smp_bt_transport, buf, len);
251 LOG_DBG("collect = %d", ret);
252
253 /*
254 * Collection can fail only due to failing to allocate memory or by receiving
255 * more data than expected.
256 */
257 if (ret == -ENOMEM) {
258 /* Failed to collect the buffer */
259 return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES);
260 } else if (ret < 0) {
261 /* Failed operation on already allocated buffer, drop the packet and report
262 * error.
263 */
264 struct smp_bt_user_data *ud =
265 (struct smp_bt_user_data *)smp_reassembly_get_ud(&smp_bt_transport);
266
267 if (ud != NULL) {
268 ud->conn = NULL;
269 ud->id = 0;
270 }
271
272 smp_reassembly_drop(&smp_bt_transport);
273 return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
274 }
275
276 if (!started) {
277 /*
278 * Transport context is attached to the buffer after first fragment
279 * has been collected.
280 */
281 struct smp_bt_user_data *ud = smp_reassembly_get_ud(&smp_bt_transport);
282
283 if (IS_ENABLED(CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL)) {
284 conn_param_smp_enable(conn);
285 }
286
287 ud->conn = conn;
288 ud->id = cpd->id;
289 }
290
291 /* No more bytes are expected for this packet */
292 if (ret == 0) {
293 smp_reassembly_complete(&smp_bt_transport, false);
294 }
295
296 /* BT expects entire len to be consumed */
297 return len;
298 #else
299 struct smp_bt_user_data *ud;
300 struct net_buf *nb;
301
302 if (cpd == NULL) {
303 LOG_ERR("Null cpd object for connection %p", (void *)conn);
304 return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES);
305 }
306
307 nb = smp_packet_alloc();
308 if (!nb) {
309 LOG_DBG("failed net_buf alloc for SMP packet");
310 return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES);
311 }
312
313 if (net_buf_tailroom(nb) < len) {
314 LOG_DBG("SMP packet len (%" PRIu16 ") > net_buf len (%zu)",
315 len, net_buf_tailroom(nb));
316 smp_packet_free(nb);
317 return BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_RESOURCES);
318 }
319
320 net_buf_add_mem(nb, buf, len);
321
322 ud = net_buf_user_data(nb);
323 ud->conn = conn;
324 ud->id = cpd->id;
325
326 if (IS_ENABLED(CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL)) {
327 conn_param_smp_enable(conn);
328 }
329
330 smp_rx_req(&smp_bt_transport, nb);
331
332 return len;
333 #endif
334 }
335
smp_bt_ccc_changed(const struct bt_gatt_attr * attr,uint16_t value)336 static void smp_bt_ccc_changed(const struct bt_gatt_attr *attr, uint16_t value)
337 {
338 #ifdef CONFIG_MCUMGR_TRANSPORT_BT_REASSEMBLY
339 if (smp_reassembly_expected(&smp_bt_transport) >= 0 && value == 0) {
340 struct smp_bt_user_data *ud = smp_reassembly_get_ud(&smp_bt_transport);
341
342 ud->conn = NULL;
343 ud->id = 0;
344
345 smp_reassembly_drop(&smp_bt_transport);
346 }
347 #endif
348 }
349
350 static struct bt_gatt_attr smp_bt_attrs[] = {
351 /* SMP Primary Service Declaration */
352 BT_GATT_PRIMARY_SERVICE(&smp_bt_svc_uuid),
353
354 BT_GATT_CHARACTERISTIC(&smp_bt_chr_uuid.uuid,
355 BT_GATT_CHRC_WRITE_WITHOUT_RESP |
356 BT_GATT_CHRC_NOTIFY,
357 #ifdef CONFIG_MCUMGR_TRANSPORT_BT_AUTHEN
358 BT_GATT_PERM_WRITE_AUTHEN,
359 #else
360 BT_GATT_PERM_WRITE,
361 #endif
362 NULL, smp_bt_chr_write, NULL),
363 BT_GATT_CCC(smp_bt_ccc_changed,
364 #ifdef CONFIG_MCUMGR_TRANSPORT_BT_AUTHEN
365 BT_GATT_PERM_READ_AUTHEN |
366 BT_GATT_PERM_WRITE_AUTHEN),
367 #else
368 BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
369 #endif
370 };
371
372 static struct bt_gatt_service smp_bt_svc = BT_GATT_SERVICE(smp_bt_attrs);
373
smp_bt_notify(struct bt_conn * conn,const void * data,uint16_t len)374 int smp_bt_notify(struct bt_conn *conn, const void *data, uint16_t len)
375 {
376 return bt_gatt_notify(conn, smp_bt_attrs + 2, data, len);
377 }
378
379 /**
380 * Extracts the Bluetooth connection from a net_buf's user data.
381 */
smp_bt_conn_from_pkt(const struct net_buf * nb)382 static struct bt_conn *smp_bt_conn_from_pkt(const struct net_buf *nb)
383 {
384 struct smp_bt_user_data *ud = net_buf_user_data(nb);
385
386 if (!ud->conn) {
387 return NULL;
388 }
389
390 return ud->conn;
391 }
392
393 /**
394 * Calculates the maximum fragment size to use when sending the specified
395 * response packet.
396 */
smp_bt_get_mtu(const struct net_buf * nb)397 static uint16_t smp_bt_get_mtu(const struct net_buf *nb)
398 {
399 struct bt_conn *conn;
400 uint16_t mtu;
401
402 conn = smp_bt_conn_from_pkt(nb);
403 if (conn == NULL) {
404 return 0;
405 }
406
407 mtu = bt_gatt_get_mtu(conn);
408
409 /* Account for the three-byte notification header. */
410 return mtu - 3;
411 }
412
smp_bt_ud_free(void * ud)413 static void smp_bt_ud_free(void *ud)
414 {
415 struct smp_bt_user_data *user_data = ud;
416
417 if (user_data->conn) {
418 user_data->conn = NULL;
419 user_data->id = 0;
420 }
421 }
422
smp_bt_ud_copy(struct net_buf * dst,const struct net_buf * src)423 static int smp_bt_ud_copy(struct net_buf *dst, const struct net_buf *src)
424 {
425 struct smp_bt_user_data *src_ud = net_buf_user_data(src);
426 struct smp_bt_user_data *dst_ud = net_buf_user_data(dst);
427
428 if (src_ud->conn) {
429 dst_ud->conn = src_ud->conn;
430 dst_ud->id = src_ud->id;
431 }
432
433 return 0;
434 }
435
436 /**
437 * Transmits the specified SMP response.
438 */
smp_bt_tx_pkt(struct net_buf * nb)439 static int smp_bt_tx_pkt(struct net_buf *nb)
440 {
441 struct bt_conn *conn;
442 int rc = MGMT_ERR_EOK;
443 uint16_t off = 0;
444 uint16_t mtu_size;
445 struct bt_gatt_notify_params notify_param = {
446 .attr = smp_bt_attrs + 2,
447 .func = smp_notify_finished,
448 .data = nb->data,
449 };
450 bool sent = false;
451 struct bt_conn_info info;
452 struct conn_param_data *cpd;
453 struct smp_bt_user_data *ud;
454
455 conn = smp_bt_conn_from_pkt(nb);
456 if (conn == NULL) {
457 rc = MGMT_ERR_ENOENT;
458 goto cleanup;
459 }
460
461 /* Verify that the device is connected, the necessity for this check is that the remote
462 * device might have sent a command and disconnected before the command has been processed
463 * completely, if this happens then the the connection details will still be valid due to
464 * the incremented connection reference count, but the connection has actually been
465 * dropped, this avoids waiting for a semaphore that will never be given which would
466 * otherwise cause a deadlock.
467 */
468 rc = bt_conn_get_info(conn, &info);
469
470 if (rc != 0 || info.state != BT_CONN_STATE_CONNECTED) {
471 /* Remote device has disconnected */
472 rc = MGMT_ERR_ENOENT;
473 goto cleanup;
474 }
475
476 /* Send data in chunks of the MTU size */
477 mtu_size = smp_bt_get_mtu(nb);
478
479 if (mtu_size == 0U) {
480 /* The transport cannot support a transmission right now. */
481 rc = MGMT_ERR_EUNKNOWN;
482 goto cleanup;
483 }
484
485 cpd = conn_param_data_get(conn);
486 ud = net_buf_user_data(nb);
487
488 if (cpd == NULL || cpd->id == 0 || cpd->id != ud->id) {
489 /* The device that sent this packet has disconnected or is not the same active
490 * connection, drop the outgoing data
491 */
492 rc = MGMT_ERR_ENOENT;
493 goto cleanup;
494 }
495
496 k_sem_reset(&cpd->smp_notify_sem);
497
498 while (off < nb->len) {
499 if (cpd->id == 0 || cpd->id != ud->id) {
500 /* The device that sent this packet has disconnected or is not the same
501 * active connection, drop the outgoing data
502 */
503 rc = MGMT_ERR_ENOENT;
504 goto cleanup;
505 }
506
507 if ((off + mtu_size) > nb->len) {
508 /* Final packet, limit size */
509 mtu_size = nb->len - off;
510 }
511
512 notify_param.len = mtu_size;
513 rc = bt_gatt_notify_cb(conn, ¬ify_param);
514
515 if (rc == -ENOMEM) {
516 if (sent == false) {
517 /* Failed to send a packet thus far, try reducing the MTU size
518 * as perhaps the buffer size is limited to a value which is
519 * less than the MTU or there is a configuration error in the
520 * project
521 */
522 if (mtu_size < SMP_BT_MINIMUM_MTU_SEND_FAILURE) {
523 /* If unable to send a 20 byte message, something is
524 * amiss, no point in continuing
525 */
526 rc = MGMT_ERR_ENOMEM;
527 break;
528 }
529
530 mtu_size /= 2;
531 }
532
533 /* No buffers available, wait until the next loop for them to become
534 * available
535 */
536 rc = MGMT_ERR_EOK;
537 k_yield();
538 } else if (rc == 0) {
539 off += mtu_size;
540 notify_param.data = &nb->data[off];
541 sent = true;
542
543 /* Wait for the completion (or disconnect) semaphore before
544 * continuing, allowing other parts of the system to run.
545 */
546 k_sem_take(&cpd->smp_notify_sem, K_FOREVER);
547 } else {
548 /* No connection, cannot continue */
549 rc = MGMT_ERR_EUNKNOWN;
550 break;
551 }
552 }
553
554 cleanup:
555 smp_bt_ud_free(net_buf_user_data(nb));
556 smp_packet_free(nb);
557
558 return rc;
559 }
560
smp_bt_register(void)561 int smp_bt_register(void)
562 {
563 return bt_gatt_service_register(&smp_bt_svc);
564 }
565
smp_bt_unregister(void)566 int smp_bt_unregister(void)
567 {
568 return bt_gatt_service_unregister(&smp_bt_svc);
569 }
570
571 /* BT connected callback. */
connected(struct bt_conn * conn,uint8_t err)572 static void connected(struct bt_conn *conn, uint8_t err)
573 {
574 if (err == 0) {
575 (void)conn_param_data_alloc(conn);
576 }
577 }
578
579 /* BT disconnected callback. */
disconnected(struct bt_conn * conn,uint8_t reason)580 static void disconnected(struct bt_conn *conn, uint8_t reason)
581 {
582 struct conn_param_data *cpd = conn_param_data_get(conn);
583
584 /* Remove all pending requests from this device which have yet to be processed from the
585 * FIFO (for this specific connection).
586 */
587 smp_rx_remove_invalid(&smp_bt_transport, (void *)conn);
588
589 /* Force giving the notification semaphore here, this is only needed if there is a pending
590 * outgoing packet when the device has disconnected, as in this case the notification
591 * callback will not be called and this is needed to prevent a deadlock.
592 */
593 if (cpd != NULL) {
594 /* Clear cpd. */
595 cpd->id = 0;
596 cpd->conn = NULL;
597
598 if (IS_ENABLED(CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL)) {
599 /* Cancel work if ongoing. */
600 (void)k_work_cancel_delayable(&cpd->dwork);
601 (void)k_work_cancel_delayable(&cpd->ework);
602
603 /* Clear cpd. */
604 cpd->state = 0;
605 }
606
607 k_sem_give(&cpd->smp_notify_sem);
608 } else {
609 LOG_ERR("Null cpd object for connection %p", (void *)conn);
610 }
611 }
612
conn_param_control_init(void)613 static void conn_param_control_init(void)
614 {
615 for (size_t i = 0; i < ARRAY_SIZE(conn_data); i++) {
616 k_work_init_delayable(&conn_data[i].dwork, conn_param_on_pref_restore);
617 k_work_init_delayable(&conn_data[i].ework, conn_param_on_error_retry);
618 }
619 }
620
smp_bt_query_valid_check(struct net_buf * nb,void * arg)621 static bool smp_bt_query_valid_check(struct net_buf *nb, void *arg)
622 {
623 const struct bt_conn *conn = (struct bt_conn *)arg;
624 struct smp_bt_user_data *ud = net_buf_user_data(nb);
625 struct conn_param_data *cpd;
626
627 if (conn == NULL || ud == NULL) {
628 return false;
629 }
630
631 cpd = conn_param_data_get(conn);
632
633 if (cpd == NULL || (ud->conn == conn && cpd->id != ud->id)) {
634 return false;
635 }
636
637 return true;
638 }
639
smp_bt_setup(void)640 static void smp_bt_setup(void)
641 {
642 int rc;
643 uint8_t i = 0;
644
645 next_id = 1;
646
647 if (IS_ENABLED(CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL)) {
648 conn_param_control_init();
649 }
650
651 while (i < CONFIG_BT_MAX_CONN) {
652 k_sem_init(&conn_data[i].smp_notify_sem, 0, 1);
653 ++i;
654 }
655
656 smp_bt_transport.functions.output = smp_bt_tx_pkt;
657 smp_bt_transport.functions.get_mtu = smp_bt_get_mtu;
658 smp_bt_transport.functions.ud_copy = smp_bt_ud_copy;
659 smp_bt_transport.functions.ud_free = smp_bt_ud_free;
660 smp_bt_transport.functions.query_valid_check = smp_bt_query_valid_check;
661
662 rc = smp_transport_init(&smp_bt_transport);
663
664 if (rc == 0) {
665 rc = smp_bt_register();
666 }
667
668 if (rc != 0) {
669 LOG_ERR("Bluetooth SMP transport register failed (err %d)", rc);
670 }
671 }
672
673 MCUMGR_HANDLER_DEFINE(smp_bt, smp_bt_setup);
674