From 9db609a973ee476b9378d012457ea93296dcf65a Mon Sep 17 00:00:00 2001 From: Lukas-Luger Date: Mon, 5 Jan 2026 16:50:47 +0100 Subject: [PATCH 01/11] drivers/netdev_ieee802154_submac: remove softack --- cpu/native/Makefile.dep | 1 - cpu/nrf52/Makefile.dep | 1 - .../netdev_ieee802154_submac/Makefile.include | 1 - .../netdev_ieee802154_submac.c | 25 +------------------ 4 files changed, 1 insertion(+), 27 deletions(-) delete mode 100644 drivers/netdev_ieee802154_submac/Makefile.include diff --git a/cpu/native/Makefile.dep b/cpu/native/Makefile.dep index 217f00ada2d9..54a9b085416f 100644 --- a/cpu/native/Makefile.dep +++ b/cpu/native/Makefile.dep @@ -43,7 +43,6 @@ ifneq (,$(filter socket_zep,$(USEMODULE))) USEMODULE += ieee802154 ifneq (,$(filter netdev,$(USEMODULE))) USEMODULE += netdev_ieee802154_submac - USEMODULE += netdev_ieee802154_submac_soft_ack endif endif diff --git a/cpu/nrf52/Makefile.dep b/cpu/nrf52/Makefile.dep index e474509e6aae..52a3444b4fdc 100644 --- a/cpu/nrf52/Makefile.dep +++ b/cpu/nrf52/Makefile.dep @@ -14,7 +14,6 @@ ifneq (,$(filter nrf802154,$(USEMODULE))) USEMODULE += luid ifneq (,$(filter netdev,$(USEMODULE))) USEMODULE += netdev_ieee802154_submac - USEMODULE += netdev_ieee802154_submac_soft_ack endif endif diff --git a/drivers/netdev_ieee802154_submac/Makefile.include b/drivers/netdev_ieee802154_submac/Makefile.include deleted file mode 100644 index 3b3230fef92c..000000000000 --- a/drivers/netdev_ieee802154_submac/Makefile.include +++ /dev/null @@ -1 +0,0 @@ -PSEUDOMODULES += netdev_ieee802154_submac_soft_ack diff --git a/drivers/netdev_ieee802154_submac/netdev_ieee802154_submac.c b/drivers/netdev_ieee802154_submac/netdev_ieee802154_submac.c index 0205f605f620..3d37367526f7 100644 --- a/drivers/netdev_ieee802154_submac/netdev_ieee802154_submac.c +++ b/drivers/netdev_ieee802154_submac/netdev_ieee802154_submac.c @@ -303,30 +303,7 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info) netdev_rx_info->lqi = rx_info.lqi; } -#if IS_USED(MODULE_NETDEV_IEEE802154_SUBMAC_SOFT_ACK) - const uint8_t *mhr = buf; - if ((mhr[0] & IEEE802154_FCF_TYPE_MASK) == IEEE802154_FCF_TYPE_DATA && - (mhr[0] & IEEE802154_FCF_ACK_REQ)) { - ieee802154_filter_mode_t mode; - if (!ieee802154_radio_has_capability(&submac->dev, IEEE802154_CAP_AUTO_ACK) && - (ieee802154_radio_get_frame_filter_mode(&submac->dev, &mode) < 0 - || mode == IEEE802154_FILTER_ACCEPT)) { - /* send ACK if not handled by the driver and not in promiscuous mode */ - uint8_t ack[IEEE802154_ACK_FRAME_LEN - IEEE802154_FCS_LEN] - = { IEEE802154_FCF_TYPE_ACK, 0x00, ieee802154_get_seq(mhr) }; - iolist_t io = { - .iol_base = ack, - .iol_len = sizeof(ack), - .iol_next = NULL - }; - DEBUG("IEEE802154 submac: Sending ACK\n"); - int snd = _send(netdev, &io); - if (snd < 0) { - DEBUG("IEEE802154 submac: failed to send ACK (%d)\n", snd); - } - } - } -#endif + return res; } From 55d81be2acbe626939010886af5a60a9bb19d22f Mon Sep 17 00:00:00 2001 From: Lukas-Luger Date: Mon, 5 Jan 2026 16:52:22 +0100 Subject: [PATCH 02/11] sys/net/link_layer/ieee802154/submac: add tx ack logic --- sys/net/link_layer/ieee802154/submac.c | 78 +++++++++++++++++--------- 1 file changed, 51 insertions(+), 27 deletions(-) diff --git a/sys/net/link_layer/ieee802154/submac.c b/sys/net/link_layer/ieee802154/submac.c index d5f5a9a2cad5..ed67e4f54ccb 100644 --- a/sys/net/link_layer/ieee802154/submac.c +++ b/sys/net/link_layer/ieee802154/submac.c @@ -67,6 +67,11 @@ static inline bool _does_handle_ack(ieee802154_dev_t *dev) ieee802154_radio_has_irq_ack_timeout(dev); } +static inline bool _does_send_ack(ieee802154_dev_t *dev) +{ + return ieee802154_radio_has_capability(dev, IEEE802154_CAP_AUTO_ACK); +} + static inline bool _does_handle_csma(ieee802154_dev_t *dev) { return ieee802154_radio_has_frame_retrans(dev) || @@ -185,26 +190,55 @@ static ieee802154_fsm_state_t _fsm_state_rx(ieee802154_submac_t *submac, ieee802 return IEEE802154_FSM_STATE_PREPARE; case IEEE802154_FSM_EV_RX_DONE: /* Make sure it's not an ACK frame */ - while (ieee802154_radio_set_idle(&submac->dev, false) < 0) {} - if (ieee802154_radio_len(&submac->dev) > (int)IEEE802154_MIN_FRAME_LEN) { + while (ieee802154_radio_set_idle(dev, false) < 0) {} + if (ieee802154_radio_len(dev) > (int)IEEE802154_MIN_FRAME_LEN) { + /* An ACK is sent synchronous to prevent that the upper layer (IPv6) + can initiate the next transmission which would fail because the transceiver + is still busy. */ + if (_does_send_ack(dev)) { + return IEEE802154_FSM_STATE_IDLE; + } + uint8_t buf[IEEE802154_FRAME_LEN_MAX]; + ieee802154_radio_read(dev, buf, IEEE802154_FRAME_LEN_MAX, NULL); + ieee802154_filter_mode_t mode; + if ((buf[0] & IEEE802154_FCF_TYPE_MASK) == IEEE802154_FCF_TYPE_DATA && + (buf[0] & IEEE802154_FCF_ACK_REQ) && + (ieee802154_radio_get_frame_filter_mode(dev, &mode) < 0 || + mode == IEEE802154_FILTER_ACCEPT)) { + + uint8_t ack[IEEE802154_ACK_FRAME_LEN - IEEE802154_FCS_LEN] + = { IEEE802154_FCF_TYPE_ACK, 0x00, ieee802154_get_seq(buf) }; + iolist_t iolist = { + .iol_base = ack, + .iol_len = sizeof(ack), + .iol_next = NULL + }; + submac->wait_for_ack = 0; + submac->psdu = &iolist; + submac->retrans = 0; + submac->csma_retries_nb = 0; + submac->backoff_mask = (1 << submac->be.min) - 1; + DEBUG("IEEE802154 submac: Sending ACK\n"); + _handle_fsm_ev_tx_ack(submac); + } submac->cb->rx_done(submac); return IEEE802154_FSM_STATE_IDLE; } else { - ieee802154_radio_read(&submac->dev, NULL, 0, NULL); + ieee802154_radio_read(dev, NULL, 0, NULL); /* If the radio doesn't support RX Continuous, go to RX */ - res = ieee802154_radio_set_rx(&submac->dev); + res = ieee802154_radio_set_rx(dev); assert(res >= 0); /* Keep on current state */ return IEEE802154_FSM_STATE_RX; } case IEEE802154_FSM_EV_CRC_ERROR: - while (ieee802154_radio_set_idle(&submac->dev, false) < 0) {} - ieee802154_radio_read(&submac->dev, NULL, 0, NULL); + while (ieee802154_radio_set_idle(dev, false) < 0) {} + ieee802154_radio_read(dev, NULL, 0, NULL); /* If the radio doesn't support RX Continuous, go to RX */ - res = ieee802154_radio_set_rx(&submac->dev); + res = ieee802154_radio_set_rx(dev); assert(res >= 0); /* Keep on current state */ return IEEE802154_FSM_STATE_RX; @@ -231,16 +265,7 @@ static ieee802154_fsm_state_t _fsm_state_idle(ieee802154_submac_t *submac, ieee8 switch (ev) { case IEEE802154_FSM_EV_REQUEST_TX: - /* An ACK is sent synchronous to prevent that the upper layer (IPv6) - can initiate the next transmission which would fail because the transceiver - is still busy. */ - if (submac->psdu->iol_len == IEEE802154_ACK_FRAME_LEN - IEEE802154_FCS_LEN && - (((uint8_t *)submac->psdu->iol_base)[0] & IEEE802154_FCF_TYPE_ACK) && - submac->psdu->iol_next == NULL) { - _handle_fsm_ev_tx_ack(submac); - return IEEE802154_FSM_STATE_IDLE; - } - else if (_handle_fsm_ev_request_tx(submac) < 0) { + if (_handle_fsm_ev_request_tx(submac) < 0) { return IEEE802154_FSM_STATE_IDLE; } return IEEE802154_FSM_STATE_PREPARE; @@ -257,7 +282,7 @@ static ieee802154_fsm_state_t _fsm_state_idle(ieee802154_submac_t *submac, ieee8 * and TX_DONE. We simply discard the frame and keep the state as * it is */ - ieee802154_radio_read(&submac->dev, NULL, 0, NULL); + ieee802154_radio_read(dev, NULL, 0, NULL); return IEEE802154_FSM_STATE_IDLE; default: break; @@ -299,7 +324,7 @@ static ieee802154_fsm_state_t _fsm_state_prepare(ieee802154_submac_t *submac, * and TX_DONE. We simply discard the frame and keep the state as * it is */ - ieee802154_radio_read(&submac->dev, NULL, 0, NULL); + ieee802154_radio_read(dev, NULL, 0, NULL); return IEEE802154_FSM_STATE_PREPARE; default: break; @@ -319,13 +344,13 @@ static ieee802154_fsm_state_t _fsm_state_tx_process_tx_done(ieee802154_submac_t switch (info->status) { case TX_STATUS_FRAME_PENDING: - assert(_does_handle_ack(&submac->dev)); + assert(_does_handle_ack(dev)); /* FALL-THRU */ case TX_STATUS_SUCCESS: submac->csma_retries_nb = 0; /* If the radio handles ACK, the TX_DONE event marks completion of * the transmission procedure. Report TX done to the upper layer */ - if (_does_handle_ack(&submac->dev) || !submac->wait_for_ack) { + if (_does_handle_ack(dev) || !submac->wait_for_ack) { return _tx_end(submac, info->status, info); } /* If the radio doesn't handle ACK, set the transceiver state to RX_ON @@ -341,7 +366,7 @@ static ieee802154_fsm_state_t _fsm_state_tx_process_tx_done(ieee802154_submac_t } break; case TX_STATUS_NO_ACK: - assert(_does_handle_ack(&submac->dev)); + assert(_does_handle_ack(dev)); submac->csma_retries_nb = 0; return _handle_tx_no_ack(submac); case TX_STATUS_MEDIUM_BUSY: @@ -349,7 +374,7 @@ static ieee802154_fsm_state_t _fsm_state_tx_process_tx_done(ieee802154_submac_t * procedure failed. We finish the SubMAC operation and report * medium busy */ - if (_does_handle_csma(&submac->dev) + if (_does_handle_csma(dev) || submac->csma_retries_nb++ >= submac->csma_retries) { return _tx_end(submac, info->status, info); } @@ -493,10 +518,9 @@ int ieee802154_send(ieee802154_submac_t *submac, const iolist_t *iolist) DEBUG("IEEE802154 submac: ieee802154_send(): Tx frame failed %s\n", str_states[current_state]); return -EBUSY; } - if (is_ack && ieee802154_submac_process_ev(submac, IEEE802154_FSM_EV_REQUEST_TX) - != IEEE802154_FSM_STATE_IDLE) { - DEBUG("IEEE802154 submac: ieee802154_send(): Tx ACK failed %s\n", str_states[current_state]); - return -EBUSY; + if (is_ack) { + DEBUG("IEEE802154 submac: ieee802154_send(): Tx ACK not permitted \n"); + return -EPERM; } return 0; } From a07216b37491107a8fe7011c9373a15a23db31aa Mon Sep 17 00:00:00 2001 From: Lukas-Luger Date: Tue, 6 Jan 2026 16:12:47 +0100 Subject: [PATCH 03/11] fixup! sys/net/link_layer/ieee802154/submac: add tx ack logic --- sys/net/link_layer/ieee802154/submac.c | 37 +++++++++++++------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/sys/net/link_layer/ieee802154/submac.c b/sys/net/link_layer/ieee802154/submac.c index ed67e4f54ccb..2f369e76051e 100644 --- a/sys/net/link_layer/ieee802154/submac.c +++ b/sys/net/link_layer/ieee802154/submac.c @@ -153,7 +153,7 @@ static ieee802154_fsm_state_t _fsm_state_prepare(ieee802154_submac_t *submac, static ieee802154_fsm_state_t _fsm_state_tx(ieee802154_submac_t *submac, ieee802154_fsm_ev_t ev); -static int _handle_fsm_ev_tx_ack(ieee802154_submac_t *submac) +static int _handle_fsm_ev_tx_ack(ieee802154_submac_t *submac, uint8_t seq_num) { ieee802154_dev_t *dev = &submac->dev; @@ -165,6 +165,19 @@ static int _handle_fsm_ev_tx_ack(ieee802154_submac_t *submac) if ((res = ieee802154_radio_write(dev, submac->psdu)) < 0) { return res; } + uint8_t ack[] + = { IEEE802154_FCF_TYPE_ACK, 0x00, seq_num }; + iolist_t iolist = { + .iol_base = ack, + .iol_len = sizeof(ack), + .iol_next = NULL + }; + submac->wait_for_ack = 0; + submac->psdu = &iolist; + submac->retrans = 0; + submac->csma_retries_nb = 0; + submac->backoff_mask = (1 << submac->be.min) - 1; + DEBUG("IEEE802154 submac: Sending ACK\n"); /* skip async Tx request */ _fsm_state_prepare(submac, IEEE802154_FSM_EV_BH, IEEE802154_FCF_TYPE_ACK); /* wait for Tx done */ @@ -192,9 +205,6 @@ static ieee802154_fsm_state_t _fsm_state_rx(ieee802154_submac_t *submac, ieee802 /* Make sure it's not an ACK frame */ while (ieee802154_radio_set_idle(dev, false) < 0) {} if (ieee802154_radio_len(dev) > (int)IEEE802154_MIN_FRAME_LEN) { - /* An ACK is sent synchronous to prevent that the upper layer (IPv6) - can initiate the next transmission which would fail because the transceiver - is still busy. */ if (_does_send_ack(dev)) { return IEEE802154_FSM_STATE_IDLE; } @@ -205,21 +215,10 @@ static ieee802154_fsm_state_t _fsm_state_rx(ieee802154_submac_t *submac, ieee802 (buf[0] & IEEE802154_FCF_ACK_REQ) && (ieee802154_radio_get_frame_filter_mode(dev, &mode) < 0 || mode == IEEE802154_FILTER_ACCEPT)) { - - uint8_t ack[IEEE802154_ACK_FRAME_LEN - IEEE802154_FCS_LEN] - = { IEEE802154_FCF_TYPE_ACK, 0x00, ieee802154_get_seq(buf) }; - iolist_t iolist = { - .iol_base = ack, - .iol_len = sizeof(ack), - .iol_next = NULL - }; - submac->wait_for_ack = 0; - submac->psdu = &iolist; - submac->retrans = 0; - submac->csma_retries_nb = 0; - submac->backoff_mask = (1 << submac->be.min) - 1; - DEBUG("IEEE802154 submac: Sending ACK\n"); - _handle_fsm_ev_tx_ack(submac); + /* An ACK is sent synchronously to prevent that the upper layer (IPv6) + can initiate the next transmission which would fail because the transceiver + is still busy. */ + _handle_fsm_ev_tx_ack(submac, ieee802154_get_seq(buf)); } submac->cb->rx_done(submac); return IEEE802154_FSM_STATE_IDLE; From ec68e3a75035945c6fea689a0906f7443c5e23ad Mon Sep 17 00:00:00 2001 From: Lukas-Luger Date: Fri, 9 Jan 2026 10:05:14 +0100 Subject: [PATCH 04/11] fixup! sys/net/link_layer/ieee802154/submac: add tx ack logic --- sys/include/net/ieee802154/submac.h | 20 ++++++++++++-------- sys/net/link_layer/ieee802154/submac.c | 14 +++++++++----- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/sys/include/net/ieee802154/submac.h b/sys/include/net/ieee802154/submac.h index 6c340d459374..7425f675f77e 100644 --- a/sys/include/net/ieee802154/submac.h +++ b/sys/include/net/ieee802154/submac.h @@ -208,6 +208,9 @@ struct ieee802154_submac { ieee802154_fsm_state_t fsm_state; /**< State of the SubMAC */ ieee802154_phy_mode_t phy_mode; /**< IEEE 802.15.4 PHY mode */ const iolist_t *psdu; /**< stores the current PSDU */ + uint8_t rx_buf[IEEE802154_FRAME_LEN_MAX]; /**< stores received frame */ + size_t rx_len; /**< stores length of received frame */ + ieee802154_rx_info_t rx_info; /**< stores lqi and rssi of received frame */ }; /** @@ -410,16 +413,13 @@ static inline int ieee802154_set_tx_power(ieee802154_submac_t *submac, /** * @brief Get the received frame length * - * @pre this function MUST be called either inside @ref ieee802154_submac_cb_t::rx_done - * or in SLEEP state. - * * @param[in] submac pointer to the SubMAC * * @return length of the PSDU (excluding FCS length) */ static inline int ieee802154_get_frame_length(ieee802154_submac_t *submac) { - return ieee802154_radio_len(&submac->dev); + return submac->rx_len; } /** @@ -427,9 +427,6 @@ static inline int ieee802154_get_frame_length(ieee802154_submac_t *submac) * * This functions reads the received PSDU from the device (excluding FCS) * - * @pre this function MUST be called either inside @ref ieee802154_submac_cb_t::rx_done - * or in SLEEP state. - * * @param[in] submac pointer to the SubMAC descriptor * @param[out] buf buffer to write into. If NULL, the packet is discarded * @param[in] len length of the buffer @@ -441,7 +438,14 @@ static inline int ieee802154_get_frame_length(ieee802154_submac_t *submac) static inline int ieee802154_read_frame(ieee802154_submac_t *submac, void *buf, size_t len, ieee802154_rx_info_t *info) { - return ieee802154_radio_read(&submac->dev, buf, len, info); + if (submac->rx_len > len) { + return -ENOBUFS; + } + if (info != NULL) { + memcpy(info, &submac->rx_info, sizeof(ieee802154_rx_info_t)); + } + memcpy(buf, submac->rx_buf, submac->rx_len); + return submac->rx_len; } /** diff --git a/sys/net/link_layer/ieee802154/submac.c b/sys/net/link_layer/ieee802154/submac.c index 2f369e76051e..c8957ea4a402 100644 --- a/sys/net/link_layer/ieee802154/submac.c +++ b/sys/net/link_layer/ieee802154/submac.c @@ -208,17 +208,16 @@ static ieee802154_fsm_state_t _fsm_state_rx(ieee802154_submac_t *submac, ieee802 if (_does_send_ack(dev)) { return IEEE802154_FSM_STATE_IDLE; } - uint8_t buf[IEEE802154_FRAME_LEN_MAX]; - ieee802154_radio_read(dev, buf, IEEE802154_FRAME_LEN_MAX, NULL); + submac->rx_len = ieee802154_radio_read(dev, submac->rx_buf, IEEE802154_FRAME_LEN_MAX, &submac->rx_info); ieee802154_filter_mode_t mode; - if ((buf[0] & IEEE802154_FCF_TYPE_MASK) == IEEE802154_FCF_TYPE_DATA && - (buf[0] & IEEE802154_FCF_ACK_REQ) && + if ((submac->rx_buf[0] & IEEE802154_FCF_TYPE_MASK) == IEEE802154_FCF_TYPE_DATA && + (submac->rx_buf[0] & IEEE802154_FCF_ACK_REQ) && (ieee802154_radio_get_frame_filter_mode(dev, &mode) < 0 || mode == IEEE802154_FILTER_ACCEPT)) { /* An ACK is sent synchronously to prevent that the upper layer (IPv6) can initiate the next transmission which would fail because the transceiver is still busy. */ - _handle_fsm_ev_tx_ack(submac, ieee802154_get_seq(buf)); + _handle_fsm_ev_tx_ack(submac, ieee802154_get_seq(submac->rx_buf)); } submac->cb->rx_done(submac); return IEEE802154_FSM_STATE_IDLE; @@ -734,6 +733,11 @@ int ieee802154_submac_init(ieee802154_submac_t *submac, const network_uint16_t * submac->fsm_state = IEEE802154_FSM_STATE_RX; + submac->rx_len = 0; + submac->rx_info.rssi = 0; + submac->rx_info.lqi = 0; + memset(submac->rx_buf, 0, sizeof(submac->rx_buf)); + int res; if ((res = ieee802154_radio_request_on(dev)) < 0) { From 4a88e62ff804c35688128b2c7a0f1d78a20be19a Mon Sep 17 00:00:00 2001 From: Lukas-Luger Date: Fri, 9 Jan 2026 13:10:19 +0100 Subject: [PATCH 05/11] fixup! sys/net/link_layer/ieee802154/submac: add tx ack logic --- sys/net/link_layer/ieee802154/submac.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sys/net/link_layer/ieee802154/submac.c b/sys/net/link_layer/ieee802154/submac.c index c8957ea4a402..e538f8efd219 100644 --- a/sys/net/link_layer/ieee802154/submac.c +++ b/sys/net/link_layer/ieee802154/submac.c @@ -208,7 +208,10 @@ static ieee802154_fsm_state_t _fsm_state_rx(ieee802154_submac_t *submac, ieee802 if (_does_send_ack(dev)) { return IEEE802154_FSM_STATE_IDLE; } - submac->rx_len = ieee802154_radio_read(dev, submac->rx_buf, IEEE802154_FRAME_LEN_MAX, &submac->rx_info); + submac->rx_len = ieee802154_radio_len(dev); + assert(submac->rx_len < IEEE802154_FRAME_LEN_MAX); + res = ieee802154_radio_read(dev, submac->rx_buf, submac->rx_len, &submac->rx_info); + assert(res == (int)submac->rx_len); ieee802154_filter_mode_t mode; if ((submac->rx_buf[0] & IEEE802154_FCF_TYPE_MASK) == IEEE802154_FCF_TYPE_DATA && (submac->rx_buf[0] & IEEE802154_FCF_ACK_REQ) && From 87b185e45028c0bb358aae7eaa70ac7e8acda296 Mon Sep 17 00:00:00 2001 From: Lukas-Luger Date: Fri, 9 Jan 2026 13:51:23 +0100 Subject: [PATCH 06/11] fixup! sys/net/link_layer/ieee802154/submac: add tx ack logic --- drivers/netdev_ieee802154_submac/netdev_ieee802154_submac.c | 2 +- sys/include/net/ieee802154/submac.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/netdev_ieee802154_submac/netdev_ieee802154_submac.c b/drivers/netdev_ieee802154_submac/netdev_ieee802154_submac.c index 3d37367526f7..aa48fbf6bcfa 100644 --- a/drivers/netdev_ieee802154_submac/netdev_ieee802154_submac.c +++ b/drivers/netdev_ieee802154_submac/netdev_ieee802154_submac.c @@ -286,7 +286,7 @@ static int _recv(netdev_t *netdev, void *buf, size_t len, void *info) netdev_ieee802154_submac_t, dev); ieee802154_submac_t *submac = &netdev_submac->submac; - ieee802154_rx_info_t rx_info; + ieee802154_rx_info_t rx_info = { 0 }; if (buf == NULL && len == 0) { return ieee802154_get_frame_length(submac); diff --git a/sys/include/net/ieee802154/submac.h b/sys/include/net/ieee802154/submac.h index 7425f675f77e..6c95df152814 100644 --- a/sys/include/net/ieee802154/submac.h +++ b/sys/include/net/ieee802154/submac.h @@ -442,7 +442,8 @@ static inline int ieee802154_read_frame(ieee802154_submac_t *submac, void *buf, return -ENOBUFS; } if (info != NULL) { - memcpy(info, &submac->rx_info, sizeof(ieee802154_rx_info_t)); + info->rssi = submac->rx_info.rssi; + info->lqi = submac->rx_info.lqi; } memcpy(buf, submac->rx_buf, submac->rx_len); return submac->rx_len; From 39b35fa84193d7cdc20bc626799ab0761f63d5db Mon Sep 17 00:00:00 2001 From: Lukas-Luger Date: Thu, 15 Jan 2026 14:34:55 +0100 Subject: [PATCH 07/11] fixup! sys/net/link_layer/ieee802154/submac: add tx ack logic --- sys/include/net/ieee802154/submac.h | 1 + sys/net/link_layer/ieee802154/submac.c | 97 +++++++++++++++----------- 2 files changed, 57 insertions(+), 41 deletions(-) diff --git a/sys/include/net/ieee802154/submac.h b/sys/include/net/ieee802154/submac.h index 6c95df152814..7a3a0531c4ec 100644 --- a/sys/include/net/ieee802154/submac.h +++ b/sys/include/net/ieee802154/submac.h @@ -167,6 +167,7 @@ typedef enum { IEEE802154_FSM_STATE_PREPARE, /**< The SubMAC is preparing the next transmission */ IEEE802154_FSM_STATE_TX, /**< The SubMAC is currently transmitting a frame */ IEEE802154_FSM_STATE_WAIT_FOR_ACK, /**< The SubMAC is waiting for an ACK frame */ + IEEE802154_FSM_STATE_TX_ACK, /**< The SubMAC is transmitting an ACK frame */ IEEE802154_FSM_STATE_NUMOF, /**< Number of SubMAC FSM states */ } ieee802154_fsm_state_t; diff --git a/sys/net/link_layer/ieee802154/submac.c b/sys/net/link_layer/ieee802154/submac.c index e538f8efd219..f7b27f410f25 100644 --- a/sys/net/link_layer/ieee802154/submac.c +++ b/sys/net/link_layer/ieee802154/submac.c @@ -48,6 +48,7 @@ static char *str_states[IEEE802154_FSM_STATE_NUMOF] = { "PREPARE", "TX", "WAIT_FOR_ACK", + "TX_ACK", }; static char *str_ev[IEEE802154_FSM_EV_NUMOF] = { @@ -155,16 +156,6 @@ static ieee802154_fsm_state_t _fsm_state_tx(ieee802154_submac_t *submac, static int _handle_fsm_ev_tx_ack(ieee802154_submac_t *submac, uint8_t seq_num) { - ieee802154_dev_t *dev = &submac->dev; - - /* Set state to TX_ON */ - int res; - if ((res = ieee802154_radio_set_idle(dev, false)) < 0) { - return res; - } - if ((res = ieee802154_radio_write(dev, submac->psdu)) < 0) { - return res; - } uint8_t ack[] = { IEEE802154_FCF_TYPE_ACK, 0x00, seq_num }; iolist_t iolist = { @@ -177,14 +168,10 @@ static int _handle_fsm_ev_tx_ack(ieee802154_submac_t *submac, uint8_t seq_num) submac->retrans = 0; submac->csma_retries_nb = 0; submac->backoff_mask = (1 << submac->be.min) - 1; + DEBUG("IEEE802154 submac: Sending ACK\n"); - /* skip async Tx request */ - _fsm_state_prepare(submac, IEEE802154_FSM_EV_BH, IEEE802154_FCF_TYPE_ACK); - /* wait for Tx done */ - while (_fsm_state_tx(submac, IEEE802154_FSM_EV_TX_DONE) == IEEE802154_FSM_STATE_INVALID) { - DEBUG("IEEE802154 submac: wait until ACK sent\n"); - } - return 0; + + return _handle_fsm_ev_request_tx(submac); } static ieee802154_fsm_state_t _fsm_state_rx(ieee802154_submac_t *submac, ieee802154_fsm_ev_t ev) @@ -202,25 +189,26 @@ static ieee802154_fsm_state_t _fsm_state_rx(ieee802154_submac_t *submac, ieee802 } return IEEE802154_FSM_STATE_PREPARE; case IEEE802154_FSM_EV_RX_DONE: - /* Make sure it's not an ACK frame */ while (ieee802154_radio_set_idle(dev, false) < 0) {} + submac->rx_len = ieee802154_radio_len(dev); + assert(submac->rx_len < IEEE802154_FRAME_LEN_MAX); + res = ieee802154_radio_read(dev, submac->rx_buf, submac->rx_len, &submac->rx_info); + assert(res == (int)submac->rx_len); + /* Make sure it's not an ACK frame */ if (ieee802154_radio_len(dev) > (int)IEEE802154_MIN_FRAME_LEN) { - if (_does_send_ack(dev)) { - return IEEE802154_FSM_STATE_IDLE; - } - submac->rx_len = ieee802154_radio_len(dev); - assert(submac->rx_len < IEEE802154_FRAME_LEN_MAX); - res = ieee802154_radio_read(dev, submac->rx_buf, submac->rx_len, &submac->rx_info); - assert(res == (int)submac->rx_len); - ieee802154_filter_mode_t mode; - if ((submac->rx_buf[0] & IEEE802154_FCF_TYPE_MASK) == IEEE802154_FCF_TYPE_DATA && - (submac->rx_buf[0] & IEEE802154_FCF_ACK_REQ) && - (ieee802154_radio_get_frame_filter_mode(dev, &mode) < 0 || - mode == IEEE802154_FILTER_ACCEPT)) { - /* An ACK is sent synchronously to prevent that the upper layer (IPv6) - can initiate the next transmission which would fail because the transceiver - is still busy. */ - _handle_fsm_ev_tx_ack(submac, ieee802154_get_seq(submac->rx_buf)); + if (!_does_send_ack(dev)) { + ieee802154_filter_mode_t mode; + if ((submac->rx_buf[0] & IEEE802154_FCF_TYPE_MASK) == IEEE802154_FCF_TYPE_DATA && + (submac->rx_buf[0] & IEEE802154_FCF_ACK_REQ) && + (ieee802154_radio_get_frame_filter_mode(dev, &mode) < 0 || + mode == IEEE802154_FILTER_ACCEPT)) { + res = _handle_fsm_ev_tx_ack(submac, ieee802154_get_seq(submac->rx_buf)); + submac->cb->rx_done(submac); + if (res < 0) { + return IEEE802154_FSM_STATE_IDLE; + } + return IEEE802154_FSM_STATE_TX_ACK; + } } submac->cb->rx_done(submac); return IEEE802154_FSM_STATE_IDLE; @@ -451,6 +439,35 @@ static ieee802154_fsm_state_t _fsm_state_wait_for_ack(ieee802154_submac_t *subma return IEEE802154_FSM_STATE_INVALID; } +static ieee802154_fsm_state_t _fsm_state_tx_ack(ieee802154_submac_t *submac, + ieee802154_fsm_ev_t ev) +{ + ieee802154_tx_info_t info; + int res; + + /* This is required to prevent unused variable warnings */ + (void) res; + + switch (ev) { + case IEEE802154_FSM_EV_TX_DONE: + if ((res = ieee802154_radio_confirm_transmit(&submac->dev, &info)) >= 0) { + return _fsm_state_tx_process_tx_done(submac, &info); + } + break; + case IEEE802154_FSM_EV_CRC_ERROR: + /* This might happen in case there's a race condition between ACK_TIMEOUT + * and TX_DONE. We simply discard the frame and keep the state as + * it is + */ + ieee802154_radio_read(&submac->dev, NULL, 0, NULL); + return IEEE802154_FSM_STATE_TX_ACK; + default: + break; + } + + return IEEE802154_FSM_STATE_INVALID; +} + ieee802154_fsm_state_t ieee802154_submac_process_ev(ieee802154_submac_t *submac, ieee802154_fsm_ev_t ev) { @@ -477,6 +494,10 @@ ieee802154_fsm_state_t ieee802154_submac_process_ev(ieee802154_submac_t *submac, DEBUG("IEEE802154 submac: ieee802154_submac_process_ev(): IEEE802154_FSM_STATE_WAIT_FOR_ACK + %s\n", str_ev[ev]); new_state = _fsm_state_wait_for_ack(submac, ev); break; + case IEEE802154_FSM_STATE_TX_ACK: + DEBUG("IEEE802154 submac: ieee802154_submac_process_ev(): IEEE802154_FSM_STATE_TX_ACK + %s\n", str_ev[ev]); + new_state = _fsm_state_tx_ack(submac, ev); + break; default: DEBUG("IEEE802154 submac: ieee802154_submac_process_ev(): INVALID STATE\n"); new_state = IEEE802154_FSM_STATE_INVALID; @@ -505,8 +526,6 @@ int ieee802154_send(ieee802154_submac_t *submac, const iolist_t *iolist) uint8_t *buf = iolist->iol_base; bool cnf = buf[0] & IEEE802154_FCF_ACK_REQ; - bool is_ack = iolist->iol_len == IEEE802154_ACK_FRAME_LEN - IEEE802154_FCS_LEN && - (buf[0] & IEEE802154_FCF_TYPE_MASK) == IEEE802154_FCF_TYPE_ACK; submac->wait_for_ack = cnf; submac->psdu = iolist; @@ -514,15 +533,11 @@ int ieee802154_send(ieee802154_submac_t *submac, const iolist_t *iolist) submac->csma_retries_nb = 0; submac->backoff_mask = (1 << submac->be.min) - 1; - if (!is_ack && ieee802154_submac_process_ev(submac, IEEE802154_FSM_EV_REQUEST_TX) + if (ieee802154_submac_process_ev(submac, IEEE802154_FSM_EV_REQUEST_TX) != IEEE802154_FSM_STATE_PREPARE) { DEBUG("IEEE802154 submac: ieee802154_send(): Tx frame failed %s\n", str_states[current_state]); return -EBUSY; } - if (is_ack) { - DEBUG("IEEE802154 submac: ieee802154_send(): Tx ACK not permitted \n"); - return -EPERM; - } return 0; } From b3bdb3bf78cd27a197e0a09448a64f0ebed7c523 Mon Sep 17 00:00:00 2001 From: Lukas-Luger Date: Thu, 22 Jan 2026 10:19:26 +0100 Subject: [PATCH 08/11] fixup! drivers/netdev_ieee802154_submac: remove softack --- drivers/netdev_ieee802154_submac/Makefile | 4 ++++ drivers/netdev_ieee802154_submac/Makefile.include | 1 + makefiles/deprecated_modules.inc.mk | 1 + 3 files changed, 6 insertions(+) create mode 100644 drivers/netdev_ieee802154_submac/Makefile.include diff --git a/drivers/netdev_ieee802154_submac/Makefile b/drivers/netdev_ieee802154_submac/Makefile index 48422e909a47..f4930fec25b2 100644 --- a/drivers/netdev_ieee802154_submac/Makefile +++ b/drivers/netdev_ieee802154_submac/Makefile @@ -1 +1,5 @@ +ifneq (,$(filter netdev_ieee802154_submac_soft_ack,$(USEMODULE))) + $(warning SubMAC Soft ACK is now on by default and will be deprecated.) +endif + include $(RIOTBASE)/Makefile.base diff --git a/drivers/netdev_ieee802154_submac/Makefile.include b/drivers/netdev_ieee802154_submac/Makefile.include new file mode 100644 index 000000000000..3b3230fef92c --- /dev/null +++ b/drivers/netdev_ieee802154_submac/Makefile.include @@ -0,0 +1 @@ +PSEUDOMODULES += netdev_ieee802154_submac_soft_ack diff --git a/makefiles/deprecated_modules.inc.mk b/makefiles/deprecated_modules.inc.mk index 5fe57d31d826..545e0e09234c 100644 --- a/makefiles/deprecated_modules.inc.mk +++ b/makefiles/deprecated_modules.inc.mk @@ -2,3 +2,4 @@ # Keep this list ALPHABETICALLY SORTED!!!!111elven DEPRECATED_MODULES += gnrc_nettype_lorawan DEPRECATED_MODULES += sema_deprecated +DEPRECATED_MODULES += netdev_ieee802154_submac_soft_ack From e0a3316559d26237690d2318452bc6a04866850b Mon Sep 17 00:00:00 2001 From: Lukas-Luger Date: Thu, 22 Jan 2026 10:20:11 +0100 Subject: [PATCH 09/11] fixup! sys/net/link_layer/ieee802154/submac: add tx ack logic --- sys/include/net/ieee802154/submac.h | 60 +++++++++++++++----------- sys/net/link_layer/ieee802154/submac.c | 14 +++--- 2 files changed, 40 insertions(+), 34 deletions(-) diff --git a/sys/include/net/ieee802154/submac.h b/sys/include/net/ieee802154/submac.h index 7a3a0531c4ec..91737a6e685e 100644 --- a/sys/include/net/ieee802154/submac.h +++ b/sys/include/net/ieee802154/submac.h @@ -30,22 +30,27 @@ * | RX | |PREPARE |<--->| TX | * | | +--->| | | | * +--------+ | +--------+ +--------+ - * ^ | ^ | - * | | | | - * | | | | - * | | +--------+ | - * | | | | v - * | | |WAIT FOR|<--------+ - * | | | ACK | | - * | | +--------+ | - * | | | | - * | | | | - * | | v | - * | | +--------+ | - * | +-----| | | - * | | IDLE | | - * +------------->| |<-------+ - * +--------+ + * | ^ | ^ | + * | | | | | + * | | | | | + * | | | +--------+ | + * | | | | | v + * | | | |WAIT FOR|<--------+ + * | | | | ACK | | + * | | | +--------+ | + * | | | | | + * | | | | | + * | | | v | + * | | | +--------+ | + * | | +-----| | | + * | | | IDLE | | + * | +----------->| |<-------+ + * | +--------+ + * | +--------+ ^ + * | | | | + * +--->| TX ACK |-----+ + * | | + * +--------+ * ``` * * - IDLE: The transceiver is off and therefore cannot receive frames. Sending @@ -71,22 +76,25 @@ * (either triggered by the radio or a timer), the SubMAC goes to either * IDLE if there are no more retransmissions left or no more CSMA-CA * retries or PREPARE otherwise. + * - TX ACK: The received frame requires instantanous acknowledgement. Sending + * further frames in this state is not permitted. After ACK transmission is + * completed, the TX DONE event will be handled as usual. * * The events that trigger state machine changes are defined in * @ref ieee802154_fsm_state_t * * The following events are valid for each state: * - * Event/State | RX | IDLE | PREPARE | TX | WAIT FOR ACK - * --------------|----|-------|---------|----|------------- - * TX_DONE | - | - | - | X | - - * RX_DONE | X | X* | X* | X* | X - * CRC_ERROR | X | X* | X* | X* | X - * ACK_TIMEOUT | - | - | - | - | X - * BH | - | - | X | - | - - * REQ_TX | X | X | - | - | - - * REQ_SET_RX_ON | - | X | - | - | - - * REQ_SET_IDLE | X | - | - | - | - + * Event/State | RX | IDLE | PREPARE | TX | WAIT FOR ACK | TX ACK | + * --------------|----|-------|---------|----|------------------------ + * TX_DONE | - | - | - | X | - |X + * RX_DONE | X | X* | X* | X* | X |- + * CRC_ERROR | X | X* | X* | X* | X |- + * ACK_TIMEOUT | - | - | - | - | X |- + * BH | - | - | X | - | - |- + * REQ_TX | X | X | - | - | - |- + * REQ_SET_RX_ON | - | X | - | - | - |- + * REQ_SET_IDLE | X | - | - | - | - |- * * *: RX_DONE and CRC_ERROR during these events might be a race condition * between the ACK Timer and the radios RX_DONE event. If this happens, the diff --git a/sys/net/link_layer/ieee802154/submac.c b/sys/net/link_layer/ieee802154/submac.c index f7b27f410f25..aa28af486e7b 100644 --- a/sys/net/link_layer/ieee802154/submac.c +++ b/sys/net/link_layer/ieee802154/submac.c @@ -97,7 +97,10 @@ static ieee802154_fsm_state_t _tx_end(ieee802154_submac_t *submac, int status, res = ieee802154_radio_set_idle(&submac->dev, true); assert(res >= 0); - submac->cb->tx_done(submac, status, info); + /* no need to inform upper layer about ACK transmission */ + if (submac->fsm_state != IEEE802154_FSM_STATE_TX_ACK) { + submac->cb->tx_done(submac, status, info); + } return IEEE802154_FSM_STATE_IDLE; } @@ -196,6 +199,7 @@ static ieee802154_fsm_state_t _fsm_state_rx(ieee802154_submac_t *submac, ieee802 assert(res == (int)submac->rx_len); /* Make sure it's not an ACK frame */ if (ieee802154_radio_len(dev) > (int)IEEE802154_MIN_FRAME_LEN) { + /* sending ACK if radio does not support auto-ACK */ if (!_does_send_ack(dev)) { ieee802154_filter_mode_t mode; if ((submac->rx_buf[0] & IEEE802154_FCF_TYPE_MASK) == IEEE802154_FCF_TYPE_DATA && @@ -205,6 +209,7 @@ static ieee802154_fsm_state_t _fsm_state_rx(ieee802154_submac_t *submac, ieee802 res = _handle_fsm_ev_tx_ack(submac, ieee802154_get_seq(submac->rx_buf)); submac->cb->rx_done(submac); if (res < 0) { + DEBUG("IEEE802154 submac: Sending ACK failed with status: %d\n", res); return IEEE802154_FSM_STATE_IDLE; } return IEEE802154_FSM_STATE_TX_ACK; @@ -454,13 +459,6 @@ static ieee802154_fsm_state_t _fsm_state_tx_ack(ieee802154_submac_t *submac, return _fsm_state_tx_process_tx_done(submac, &info); } break; - case IEEE802154_FSM_EV_CRC_ERROR: - /* This might happen in case there's a race condition between ACK_TIMEOUT - * and TX_DONE. We simply discard the frame and keep the state as - * it is - */ - ieee802154_radio_read(&submac->dev, NULL, 0, NULL); - return IEEE802154_FSM_STATE_TX_ACK; default: break; } From 8c6dc3425d3ca026d28f46706df5aecddae80479 Mon Sep 17 00:00:00 2001 From: Lukas-Luger Date: Thu, 22 Jan 2026 12:40:30 +0100 Subject: [PATCH 10/11] fixup! sys/net/link_layer/ieee802154/submac: add tx ack logic --- sys/include/net/ieee802154/submac.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sys/include/net/ieee802154/submac.h b/sys/include/net/ieee802154/submac.h index 91737a6e685e..4cc9150db3ca 100644 --- a/sys/include/net/ieee802154/submac.h +++ b/sys/include/net/ieee802154/submac.h @@ -57,8 +57,9 @@ * frames might be triggered using @ref ieee802154_send. The next SubMAC * state would be PREPARE. * - RX: The device is ready to receive frames. In case the SubMAC receives a - * frame it will call @ref ieee802154_submac_cb_t::rx_done and immediately go - * to IDLE. Same as the IDLE state, it's possible + * frame it will transmit an ACK frame if necessary then call + * @ref ieee802154_submac_cb_t::rx_done and immediately go + * to IDLE or TX ACK. Same as the IDLE state, it's possible * to trigger frames using @ref ieee802154_send. * - PREPARE: The frame is already in the framebuffer and waiting to be * transmitted. This state might handle CSMA-CA backoff timer in case the From 22683b3257a2cfb8591e6a30c38a481d04b1bb32 Mon Sep 17 00:00:00 2001 From: Lukas-Luger Date: Thu, 22 Jan 2026 12:42:13 +0100 Subject: [PATCH 11/11] fixup! sys/net/link_layer/ieee802154/submac: add tx ack logic --- sys/include/net/ieee802154/submac.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/include/net/ieee802154/submac.h b/sys/include/net/ieee802154/submac.h index 4cc9150db3ca..eebf58b65457 100644 --- a/sys/include/net/ieee802154/submac.h +++ b/sys/include/net/ieee802154/submac.h @@ -79,7 +79,7 @@ * retries or PREPARE otherwise. * - TX ACK: The received frame requires instantanous acknowledgement. Sending * further frames in this state is not permitted. After ACK transmission is - * completed, the TX DONE event will be handled as usual. + * completed, the SubMAC will go IDLE. * * The events that trigger state machine changes are defined in * @ref ieee802154_fsm_state_t