diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index c3dd892e7825..392d8698a857 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -58,7 +58,7 @@ static struct { const struct bt_mesh_send_cb *cb; void *cb_data; uint64_t timestamp; - struct k_delayed_work work; + struct k_work_delayable work; } adv; static int adv_start(const struct bt_le_adv_param *param, @@ -201,7 +201,7 @@ static void schedule_send(void) * to the previous packet than what's permitted by the specification. */ delta = k_uptime_delta(×tamp); - k_delayed_work_submit(&adv.work, K_MSEC(ADV_INT_FAST_MS - delta)); + k_work_reschedule(&adv.work, K_MSEC(ADV_INT_FAST_MS - delta)); } void bt_mesh_adv_update(void) @@ -218,7 +218,7 @@ void bt_mesh_adv_buf_ready(void) void bt_mesh_adv_init(void) { - k_delayed_work_init(&adv.work, send_pending_adv); + k_work_init_delayable(&adv.work, send_pending_adv); } static void adv_sent(struct bt_le_ext_adv *instance, diff --git a/subsys/bluetooth/mesh/friend.c b/subsys/bluetooth/mesh/friend.c index 285f479df1b7..b33127f2303c 100644 --- a/subsys/bluetooth/mesh/friend.c +++ b/subsys/bluetooth/mesh/friend.c @@ -67,6 +67,11 @@ static struct bt_mesh_adv *adv_alloc(int id) return &adv_pool[id].adv; } +static bool friend_is_allocated(const struct bt_mesh_friend *frnd) +{ + return frnd->subnet != NULL; +} + static bool is_lpn_unicast(struct bt_mesh_friend *frnd, uint16_t addr) { if (frnd->lpn == BT_MESH_ADDR_UNASSIGNED) { @@ -86,7 +91,7 @@ struct bt_mesh_friend *bt_mesh_friend_find(uint16_t net_idx, uint16_t lpn_addr, for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - if (valid && !frnd->subnet) { + if (valid && !friend_is_allocated(frnd)) { continue; } @@ -149,7 +154,8 @@ static void friend_clear(struct bt_mesh_friend *frnd) BT_DBG("LPN 0x%04x", frnd->lpn); - k_delayed_work_cancel(&frnd->timer); + /* If cancelling the timer fails, we'll exit early in the work handler. */ + (void)k_work_cancel_delayable(&frnd->timer); memset(frnd->cred, 0, sizeof(frnd->cred)); @@ -197,7 +203,7 @@ void bt_mesh_friends_clear(void) for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - if (!frnd->subnet) { + if (!friend_is_allocated(frnd)) { continue; } @@ -216,7 +222,7 @@ void bt_mesh_friend_sec_update(uint16_t net_idx) for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - if (!frnd->subnet) { + if (!friend_is_allocated(frnd)) { continue; } @@ -531,7 +537,7 @@ static struct net_buf *encode_update(struct bt_mesh_friend *frnd, uint8_t md) struct bt_mesh_ctl_friend_update *upd; NET_BUF_SIMPLE_DEFINE(sdu, 1 + sizeof(*upd)); - __ASSERT_NO_MSG(frnd->subnet); + __ASSERT_NO_MSG(friend_is_allocated(frnd)); BT_DBG("lpn 0x%04x md 0x%02x", frnd->lpn, md); @@ -582,7 +588,7 @@ static void friend_recv_delay(struct bt_mesh_friend *frnd) int32_t delay = recv_delay(frnd); frnd->pending_req = 1U; - k_delayed_work_submit(&frnd->timer, K_MSEC(delay)); + k_work_reschedule(&frnd->timer, K_MSEC(delay)); BT_DBG("Waiting RecvDelay of %d ms", delay); } @@ -762,8 +768,8 @@ static void friend_clear_sent(int err, void *user_data) { struct bt_mesh_friend *frnd = user_data; - k_delayed_work_submit(&frnd->clear.timer, - K_SECONDS(frnd->clear.repeat_sec)); + k_work_reschedule(&frnd->clear.timer, + K_SECONDS(frnd->clear.repeat_sec)); frnd->clear.repeat_sec *= 2U; } @@ -798,10 +804,16 @@ static void send_friend_clear(struct bt_mesh_friend *frnd) static void clear_timeout(struct k_work *work) { - struct bt_mesh_friend *frnd = CONTAINER_OF(work, struct bt_mesh_friend, - clear.timer.work); + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct bt_mesh_friend *frnd = CONTAINER_OF(dwork, struct bt_mesh_friend, + clear.timer); uint32_t duration; + if (frnd->clear.frnd == BT_MESH_ADDR_UNASSIGNED) { + /* Failed cancelling timer, return early. */ + return; + } + BT_DBG("LPN 0x%04x (old) Friend 0x%04x", frnd->lpn, frnd->clear.frnd); duration = k_uptime_get_32() - frnd->clear.start; @@ -858,7 +870,8 @@ int bt_mesh_friend_clear_cfm(struct bt_mesh_net_rx *rx, return 0; } - k_delayed_work_cancel(&frnd->clear.timer); + /* If this fails, the unassigned check will make the handler return early. */ + (void)k_work_cancel_delayable(&frnd->clear.timer); frnd->clear.frnd = BT_MESH_ADDR_UNASSIGNED; return 0; @@ -1028,7 +1041,7 @@ int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf) } delay = offer_delay(frnd, rx->ctx.recv_rssi, msg->criteria); - k_delayed_work_submit(&frnd->timer, K_MSEC(delay)); + k_work_reschedule(&frnd->timer, K_MSEC(delay)); enqueue_offer(frnd, rx->ctx.recv_rssi); @@ -1145,11 +1158,12 @@ static void buf_send_end(int err, void *user_data) } if (frnd->established) { - k_delayed_work_submit(&frnd->timer, K_MSEC(frnd->poll_to)); + /* Always restart poll timeout timer after sending */ + k_work_reschedule(&frnd->timer, K_MSEC(frnd->poll_to)); BT_DBG("Waiting %u ms for next poll", frnd->poll_to); } else { /* Friend offer timeout is 1 second */ - k_delayed_work_submit(&frnd->timer, K_SECONDS(1)); + k_work_reschedule(&frnd->timer, K_SECONDS(1)); BT_DBG("Waiting for first poll"); } } @@ -1188,15 +1202,19 @@ static void update_overwrite(struct net_buf *buf, uint8_t md) static void friend_timeout(struct k_work *work) { - struct bt_mesh_friend *frnd = CONTAINER_OF(work, struct bt_mesh_friend, - timer.work); + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct bt_mesh_friend *frnd = CONTAINER_OF(dwork, struct bt_mesh_friend, + timer); static const struct bt_mesh_send_cb buf_sent_cb = { .start = buf_send_start, .end = buf_send_end, }; - uint8_t md; + if (!friend_is_allocated(frnd)) { + return; + } + __ASSERT_NO_MSG(frnd->pending_buf == 0U); BT_DBG("lpn 0x%04x send_last %u last %p", frnd->lpn, @@ -1301,8 +1319,8 @@ int bt_mesh_friend_init(void) sys_slist_init(&frnd->queue); - k_delayed_work_init(&frnd->timer, friend_timeout); - k_delayed_work_init(&frnd->clear.timer, clear_timeout); + k_work_init_delayable(&frnd->timer, friend_timeout); + k_work_init_delayable(&frnd->clear.timer, clear_timeout); for (j = 0; j < ARRAY_SIZE(frnd->seg); j++) { sys_slist_init(&frnd->seg[j].queue); diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index 0f16e0c7c4df..2f8f00129442 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -174,7 +174,11 @@ void bt_mesh_reset(void) memset(bt_mesh.flags, 0, sizeof(bt_mesh.flags)); - k_delayed_work_cancel(&bt_mesh.ivu_timer); + /* If this fails, the work handler will return early on the next + * execution, as the device is not provisioned. If the device is + * reprovisioned, the timer is always restarted. + */ + (void)k_work_cancel_delayable(&bt_mesh.ivu_timer); bt_mesh_cfg_reset(); bt_mesh_trans_reset(); diff --git a/subsys/bluetooth/mesh/net.c b/subsys/bluetooth/mesh/net.c index aadeab35a17d..df2bffb1adb5 100644 --- a/subsys/bluetooth/mesh/net.c +++ b/subsys/bluetooth/mesh/net.c @@ -306,7 +306,7 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) bt_mesh.seq = 0U; } - k_delayed_work_submit(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); + k_work_reschedule(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); /* Notify other modules */ if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { @@ -844,6 +844,10 @@ void bt_mesh_net_recv(struct net_buf_simple *data, int8_t rssi, static void ivu_refresh(struct k_work *work) { + if (!bt_mesh_is_provisioned()) { + return; + } + bt_mesh.ivu_duration = MIN(UINT8_MAX, bt_mesh.ivu_duration + BT_MESH_IVU_HOURS); @@ -857,7 +861,7 @@ static void ivu_refresh(struct k_work *work) store_iv(true); } - k_delayed_work_submit(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); + k_work_reschedule(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); return; } @@ -871,7 +875,7 @@ static void ivu_refresh(struct k_work *work) void bt_mesh_net_init(void) { - k_delayed_work_init(&bt_mesh.ivu_timer, ivu_refresh); + k_work_init_delayable(&bt_mesh.ivu_timer, ivu_refresh); k_work_init(&bt_mesh.local_work, bt_mesh_net_local); } @@ -1080,6 +1084,6 @@ void bt_mesh_net_clear(void) void bt_mesh_net_settings_commit(void) { if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) { - k_delayed_work_submit(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); + k_work_reschedule(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); } } diff --git a/subsys/bluetooth/mesh/net.h b/subsys/bluetooth/mesh/net.h index e93fd1149202..e92124439086 100644 --- a/subsys/bluetooth/mesh/net.h +++ b/subsys/bluetooth/mesh/net.h @@ -66,7 +66,7 @@ struct bt_mesh_friend { uint16_t sub_list[FRIEND_SUB_LIST_SIZE]; - struct k_delayed_work timer; + struct k_work_delayable timer; struct bt_mesh_friend_seg { sys_slist_t queue; @@ -88,7 +88,7 @@ struct bt_mesh_friend { uint32_t start; /* Clear Procedure start */ uint16_t frnd; /* Previous Friend's address */ uint16_t repeat_sec; /* Repeat timeout in seconds */ - struct k_delayed_work timer; /* Repeat timer */ + struct k_work_delayable timer; /* Repeat timer */ } clear; }; @@ -213,7 +213,7 @@ struct bt_mesh_net { uint8_t default_ttl; /* Timer to track duration in current IV Update state */ - struct k_delayed_work ivu_timer; + struct k_work_delayable ivu_timer; uint8_t dev_key[16]; }; diff --git a/subsys/bluetooth/mesh/pb_adv.c b/subsys/bluetooth/mesh/pb_adv.c index 6503e6d99f78..eb57d60c313c 100644 --- a/subsys/bluetooth/mesh/pb_adv.c +++ b/subsys/bluetooth/mesh/pb_adv.c @@ -104,11 +104,11 @@ struct pb_adv { void *cb_data; /* Retransmit timer */ - struct k_delayed_work retransmit; + struct k_work_delayable retransmit; } tx; /* Protocol timeout */ - struct k_delayed_work prot_timer; + struct k_work_delayable prot_timer; }; struct prov_rx { @@ -133,7 +133,7 @@ static void buf_sent(int err, void *user_data) return; } - k_delayed_work_submit(&link.tx.retransmit, RETRANSMIT_TIMEOUT); + k_work_reschedule(&link.tx.retransmit, RETRANSMIT_TIMEOUT); } static struct bt_mesh_send_cb buf_sent_cb = { @@ -178,7 +178,12 @@ static void prov_clear_tx(void) { BT_DBG(""); - k_delayed_work_cancel(&link.tx.retransmit); + /* If this fails, the work handler will not find any buffers to send, + * and return without rescheduling. The work handler also checks the + * LINK_ACTIVE flag, so if this call is part of reset_adv_link, it'll + * exit early. + */ + (void)k_work_cancel_delayable(&link.tx.retransmit); free_segments(); } @@ -188,7 +193,10 @@ static void reset_adv_link(void) BT_DBG(""); prov_clear_tx(); - k_delayed_work_cancel(&link.prot_timer); + /* If this fails, the work handler will exit early on the LINK_ACTIVE + * check. + */ + (void)k_work_cancel_delayable(&link.prot_timer); if (atomic_test_bit(link.flags, ADV_PROVISIONER)) { /* Clear everything except the retransmit and protocol timer @@ -253,7 +261,7 @@ static void prov_failed(uint8_t err) static void prov_msg_recv(void) { - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); + k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); if (!bt_mesh_fcs_check(link.rx.buf, link.rx.fcs)) { BT_ERR("Incorrect FCS"); @@ -274,6 +282,10 @@ static void prov_msg_recv(void) static void protocol_timeout(struct k_work *work) { + if (!atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) { + return; + } + BT_DBG(""); link.rx.seg = 0U; @@ -557,6 +569,12 @@ static void send_reliable(void) break; } + if (BT_MESH_ADV(buf)->busy) { + continue; + } + + BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); + if (i + 1 < ARRAY_SIZE(link.tx.buf) && link.tx.buf[i + 1]) { bt_mesh_adv_send(buf, NULL, NULL); } else { @@ -568,7 +586,6 @@ static void send_reliable(void) static void prov_retransmit(struct k_work *work) { int32_t timeout_ms; - int i; BT_DBG(""); @@ -599,25 +616,7 @@ static void prov_retransmit(struct k_work *work) return; } - for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) { - struct net_buf *buf = link.tx.buf[i]; - - if (!buf) { - break; - } - - if (BT_MESH_ADV(buf)->busy) { - continue; - } - - BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len)); - - if (i + 1 < ARRAY_SIZE(link.tx.buf) && link.tx.buf[i + 1]) { - bt_mesh_adv_send(buf, NULL, NULL); - } else { - bt_mesh_adv_send(buf, &buf_sent_cb, NULL); - } - } + send_reliable(); } static int bearer_ctl_send(uint8_t op, const void *data, uint8_t data_len, @@ -628,7 +627,7 @@ static int bearer_ctl_send(uint8_t op, const void *data, uint8_t data_len, BT_DBG("op 0x%02x data_len %u", op, data_len); prov_clear_tx(); - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); + k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); buf = adv_buf_create(reliable ? RETRANSMITS_RELIABLE : RETRANSMITS_UNRELIABLE); @@ -660,7 +659,7 @@ static int prov_send_adv(struct net_buf_simple *msg, uint8_t seg_len, seg_id; prov_clear_tx(); - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); + k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); start = adv_buf_create(RETRANSMITS_RELIABLE); if (!start) { @@ -884,8 +883,8 @@ static void prov_link_close(enum prov_bearer_link_status status) void pb_adv_init(void) { - k_delayed_work_init(&link.prot_timer, protocol_timeout); - k_delayed_work_init(&link.tx.retransmit, prov_retransmit); + k_work_init_delayable(&link.prot_timer, protocol_timeout); + k_work_init_delayable(&link.tx.retransmit, prov_retransmit); } void pb_adv_reset(void) diff --git a/subsys/bluetooth/mesh/pb_gatt.c b/subsys/bluetooth/mesh/pb_gatt.c index 4e36fd7e9fc9..e591b7abe177 100644 --- a/subsys/bluetooth/mesh/pb_gatt.c +++ b/subsys/bluetooth/mesh/pb_gatt.c @@ -22,7 +22,7 @@ struct prov_link { const struct prov_bearer_cb *cb; void *cb_data; struct net_buf_simple *rx_buf; - struct k_delayed_work prot_timer; + struct k_work_delayable prot_timer; }; static struct prov_link link; @@ -34,7 +34,8 @@ static void reset_state(void) link.conn = NULL; } - k_delayed_work_cancel(&link.prot_timer); + /* If this fails, the protocol timeout handler will exit early. */ + (void)k_work_cancel_delayable(&link.prot_timer); link.rx_buf = bt_mesh_proxy_get_buf(); } @@ -51,8 +52,12 @@ static void link_closed(enum prov_bearer_link_status status) static void protocol_timeout(struct k_work *work) { - BT_DBG("Protocol timeout"); + if (!link.conn) { + /* Already disconnected */ + return; + } + BT_DBG("Protocol timeout"); link_closed(PROV_BEARER_LINK_STATUS_TIMEOUT); } @@ -70,7 +75,7 @@ int bt_mesh_pb_gatt_recv(struct bt_conn *conn, struct net_buf_simple *buf) return -EINVAL; } - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); + k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); link.cb->recv(&pb_gatt, link.cb_data, buf); @@ -86,7 +91,7 @@ int bt_mesh_pb_gatt_open(struct bt_conn *conn) } link.conn = bt_conn_ref(conn); - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); + k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); link.cb->link_opened(&pb_gatt, link.cb_data); @@ -125,7 +130,7 @@ static int buf_send(struct net_buf_simple *buf, prov_bearer_send_complete_t cb, return -ENOTCONN; } - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); + k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); return bt_mesh_proxy_send(link.conn, BT_MESH_PROXY_PROV, buf); } @@ -137,7 +142,7 @@ static void clear_tx(void) void pb_gatt_init(void) { - k_delayed_work_init(&link.prot_timer, protocol_timeout); + k_work_init_delayable(&link.prot_timer, protocol_timeout); } void pb_gatt_reset(void) diff --git a/subsys/bluetooth/mesh/proxy.c b/subsys/bluetooth/mesh/proxy.c index 965d0a76edf0..6f08f2e5f221 100644 --- a/subsys/bluetooth/mesh/proxy.c +++ b/subsys/bluetooth/mesh/proxy.c @@ -96,7 +96,7 @@ static struct bt_mesh_proxy_client { #if defined(CONFIG_BT_MESH_GATT_PROXY) struct k_work send_beacons; #endif - struct k_delayed_work sar_timer; + struct k_work_delayable sar_timer; struct net_buf_simple buf; } clients[CONFIG_BT_MAX_CONN] = { [0 ... (CONFIG_BT_MAX_CONN - 1)] = { @@ -132,15 +132,22 @@ static struct bt_mesh_proxy_client *find_client(struct bt_conn *conn) static void proxy_sar_timeout(struct k_work *work) { - struct bt_mesh_proxy_client *client; + struct k_work_delayable *dwork = k_work_delayable_from_work(work); + struct bt_mesh_proxy_client *client = + CONTAINER_OF(dwork, struct bt_mesh_proxy_client, sar_timer); - BT_WARN("Proxy SAR timeout"); + if (!client->conn) { + return; + } - client = CONTAINER_OF(work, struct bt_mesh_proxy_client, sar_timer); - if (client->conn) { - bt_conn_disconnect(client->conn, - BT_HCI_ERR_REMOTE_USER_TERM_CONN); + if (!client->buf.len) { + BT_DBG("No pending Proxy SAR message"); + return; } + + BT_WARN("Proxy SAR timeout"); + + bt_conn_disconnect(client->conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); } #if defined(CONFIG_BT_MESH_GATT_PROXY) @@ -501,7 +508,7 @@ static ssize_t proxy_recv(struct bt_conn *conn, return -EINVAL; } - k_delayed_work_submit(&client->sar_timer, PROXY_SAR_TIMEOUT); + k_work_reschedule(&client->sar_timer, PROXY_SAR_TIMEOUT); client->msg_type = PDU_TYPE(data); net_buf_simple_add_mem(&client->buf, data + 1, len - 1); break; @@ -517,7 +524,7 @@ static ssize_t proxy_recv(struct bt_conn *conn, return -EINVAL; } - k_delayed_work_submit(&client->sar_timer, PROXY_SAR_TIMEOUT); + k_work_reschedule(&client->sar_timer, PROXY_SAR_TIMEOUT); net_buf_simple_add_mem(&client->buf, data + 1, len - 1); break; @@ -532,7 +539,10 @@ static ssize_t proxy_recv(struct bt_conn *conn, return -EINVAL; } - k_delayed_work_cancel(&client->sar_timer); + /* If this fails, the work handler exits early, as there's no + * active SAR buffer. + */ + (void)k_work_cancel_delayable(&client->sar_timer); net_buf_simple_add_mem(&client->buf, data + 1, len - 1); proxy_complete_pdu(client); break; @@ -592,7 +602,10 @@ static void proxy_disconnected(struct bt_conn *conn, uint8_t reason) bt_mesh_pb_gatt_close(conn); } - k_delayed_work_cancel(&client->sar_timer); + /* If this fails, the work handler exits early, as + * there's no active connection. + */ + (void)k_work_cancel_delayable(&client->sar_timer); bt_conn_unref(client->conn); client->conn = NULL; break; @@ -1368,7 +1381,7 @@ int bt_mesh_proxy_init(void) client->buf.size = CLIENT_BUF_SIZE; client->buf.__buf = client_buf_data + (i * CLIENT_BUF_SIZE); - k_delayed_work_init(&client->sar_timer, proxy_sar_timeout); + k_work_init_delayable(&client->sar_timer, proxy_sar_timeout); } bt_conn_cb_register(&conn_callbacks); diff --git a/subsys/bluetooth/mesh/transport.c b/subsys/bluetooth/mesh/transport.c index c9cb93dbcc3e..54df08bcd540 100644 --- a/subsys/bluetooth/mesh/transport.c +++ b/subsys/bluetooth/mesh/transport.c @@ -115,7 +115,7 @@ static struct seg_tx { friend_cred:1; /* Using Friend credentials */ const struct bt_mesh_send_cb *cb; void *cb_data; - struct k_delayed_work retransmit; /* Retransmit timer */ + struct k_work_delayable retransmit; /* Retransmit timer */ } seg_tx[CONFIG_BT_MESH_TX_SEG_MSG_COUNT]; static struct seg_rx { @@ -133,7 +133,7 @@ static struct seg_rx { uint8_t ttl; uint32_t block; uint32_t last; - struct k_delayed_work ack; + struct k_work_delayable ack; } seg_rx[CONFIG_BT_MESH_RX_SEG_MSG_COUNT]; K_MEM_SLAB_DEFINE(segs, BT_MESH_APP_SEG_SDU_MAX, CONFIG_BT_MESH_SEG_BUFS, 4); @@ -247,7 +247,7 @@ static void seg_tx_unblock_check(struct seg_tx *tx) BT_DBG("Unblocked 0x%04x", (uint16_t)(blocked->seq_auth & TRANS_SEQ_ZERO_MASK)); blocked->blocked = false; - k_delayed_work_submit(&blocked->retransmit, K_NO_WAIT); + k_work_reschedule(&blocked->retransmit, K_NO_WAIT); } } @@ -255,7 +255,8 @@ static void seg_tx_reset(struct seg_tx *tx) { int i; - k_delayed_work_cancel(&tx->retransmit); + /* If this call fails, the handler will exit early, as nack_count is 0. */ + (void)k_work_cancel_delayable(&tx->retransmit); tx->cb = NULL; tx->cb_data = NULL; @@ -315,9 +316,9 @@ static void schedule_retransmit(struct seg_tx *tx) * called this from inside bt_mesh_net_send), we should continue the * retransmit immediately, as we just freed up a tx buffer. */ - k_delayed_work_submit(&tx->retransmit, - tx->seg_o ? K_NO_WAIT : - K_MSEC(SEG_RETRANSMIT_TIMEOUT(tx))); + k_work_reschedule(&tx->retransmit, + tx->seg_o ? K_NO_WAIT : + K_MSEC(SEG_RETRANSMIT_TIMEOUT(tx))); } static void seg_send_start(uint16_t duration, int err, void *user_data) @@ -440,8 +441,8 @@ static void seg_tx_send_unacked(struct seg_tx *tx) end: if (!tx->seg_pending) { - k_delayed_work_submit(&tx->retransmit, - K_MSEC(SEG_RETRANSMIT_TIMEOUT(tx))); + k_work_reschedule(&tx->retransmit, + K_MSEC(SEG_RETRANSMIT_TIMEOUT(tx))); } tx->sending = 0U; @@ -859,8 +860,6 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, return -EINVAL; } - k_delayed_work_cancel(&tx->retransmit); - while ((bit = find_lsb_set(ack))) { if (tx->seg[bit - 1]) { BT_DBG("seg %u/%u acked", bit - 1, tx->seg_n); @@ -871,7 +870,11 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, } if (tx->nack_count) { - seg_tx_send_unacked(tx); + /* According to the Bluetooth Mesh Profile specification, + * section 3.5.3.3, we should reset the retransmit timer and + * retransmit immediately when receiving a valid ack message: + */ + k_work_reschedule(&tx->retransmit, K_NO_WAIT); } else { BT_DBG("SDU TX complete"); seg_tx_complete(tx, 0); @@ -1090,7 +1093,10 @@ static void seg_rx_reset(struct seg_rx *rx, bool full_reset) BT_DBG("rx %p", rx); - k_delayed_work_cancel(&rx->ack); + /* If this fails, the handler will exit early on the next execution, as + * it checks rx->in_use. + */ + (void)k_work_cancel_delayable(&rx->ack); if (IS_ENABLED(CONFIG_BT_MESH_FRIEND) && rx->obo && rx->block != BLOCK_COMPLETE(rx->seg_n)) { @@ -1127,6 +1133,16 @@ static void seg_ack(struct k_work *work) struct seg_rx *rx = CONTAINER_OF(work, struct seg_rx, ack); int32_t timeout; + if (!rx->in_use || rx->block == BLOCK_COMPLETE(rx->seg_n)) { + /* Cancellation of this timer may have failed. If it fails as + * part of seg_reset, in_use will be false. + * If it fails as part of the processing of a fully received + * SDU, the ack is already being sent from the receive handler, + * and the timer based ack sending can be ignored. + */ + return; + } + BT_DBG("rx %p", rx); if (k_uptime_get_32() - rx->last > (60 * MSEC_PER_SEC)) { @@ -1144,7 +1160,7 @@ static void seg_ack(struct k_work *work) rx->block, rx->obo); timeout = ack_timeout(rx); - k_delayed_work_submit(&rx->ack, K_MSEC(timeout)); + k_work_schedule(&rx->ack, K_MSEC(timeout)); } static inline bool sdu_len_is_ok(bool ctl, uint8_t seg_n) @@ -1447,11 +1463,10 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, /* Reset the Incomplete Timer */ rx->last = k_uptime_get_32(); - if (!k_delayed_work_remaining_get(&rx->ack) && - !bt_mesh_lpn_established()) { + if (!bt_mesh_lpn_established()) { int32_t timeout = ack_timeout(rx); - - k_delayed_work_submit(&rx->ack, K_MSEC(timeout)); + /* Should only start ack timer if it isn't running already: */ + k_work_schedule(&rx->ack, K_MSEC(timeout)); } /* Allocated segment here */ @@ -1487,7 +1502,10 @@ static int trans_seg(struct net_buf_simple *buf, struct bt_mesh_net_rx *net_rx, *pdu_type = BT_MESH_FRIEND_PDU_COMPLETE; - k_delayed_work_cancel(&rx->ack); + /* If this fails, the work handler will either exit early because the + * block is fully received, or rx->in_use is false. + */ + (void)k_work_cancel_delayable(&rx->ack); send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, net_rx->ctx.send_ttl, seq_auth, rx->block, rx->obo); @@ -1643,11 +1661,11 @@ void bt_mesh_trans_init(void) int i; for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { - k_delayed_work_init(&seg_tx[i].retransmit, seg_retransmit); + k_work_init_delayable(&seg_tx[i].retransmit, seg_retransmit); } for (i = 0; i < ARRAY_SIZE(seg_rx); i++) { - k_delayed_work_init(&seg_rx[i].ack, seg_ack); + k_work_init_delayable(&seg_rx[i].ack, seg_ack); } }