This is an automated email from the ASF dual-hosted git repository. xiaoxiang781216 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 86bd7f0edc3f0e568fd43fa5b0db703fd659fe12 Author: raiden00pl <[email protected]> AuthorDate: Thu Oct 22 14:58:41 2026 +0200 wireless/ieee802154: free the frame and the confirm with the TX descriptor The TX descriptor owns its frame and its confirm primitive, but each user freed them by hand, and MCPS-DATA.request freed the descriptor without its confirm on every error exit, leaking a primitive. mac802154_txdesc_free() frees both; a user that hands the confirm to the next layer takes it out of the descriptor first. Assisted-by: Claude Code Signed-off-by: raiden00pl <[email protected]> --- wireless/ieee802154/mac802154.c | 21 +++++---------------- wireless/ieee802154/mac802154_assoc.c | 16 ++++------------ wireless/ieee802154/mac802154_data.c | 2 +- wireless/ieee802154/mac802154_internal.h | 26 ++++++++++++++++++++++++++ wireless/ieee802154/mac802154_poll.c | 6 +----- 5 files changed, 37 insertions(+), 34 deletions(-) diff --git a/wireless/ieee802154/mac802154.c b/wireless/ieee802154/mac802154.c index a8e2913f7d0..d9aa3d5c0c1 100644 --- a/wireless/ieee802154/mac802154.c +++ b/wireless/ieee802154/mac802154.c @@ -775,11 +775,8 @@ static void mac802154_purge_worker(FAR void *arg) sq_remfirst(&priv->indirect_queue); - /* Free the IOB, the notification, and the tx descriptor */ + /* Free the tx descriptor with the frame and the confirm */ - iob_free(txdesc->frame); - ieee802154_primitive_free((FAR struct ieee802154_primitive_s *) - txdesc->conf); mac802154_txdesc_free(priv, txdesc); priv->beaconupdate = true; @@ -926,12 +923,6 @@ static void mac802154_txdone_worker(FAR void *arg) break; } - /* Cast the data_conf to a notification. We get both the private and - * public notification structure to make it easier to use. - */ - - primitive = (FAR struct ieee802154_primitive_s *)txdesc->conf; - wlinfo("Tx status: %s\n", g_ieee802154_status_string[txdesc->conf->status]); @@ -939,6 +930,9 @@ static void mac802154_txdone_worker(FAR void *arg) { case IEEE802154_FRAME_DATA: { + /* The data confirm goes to the next layer */ + + primitive = mac802154_txdesc_takeconf(txdesc); primitive->type = IEEE802154_PRIMITIVE_CONF_DATA; mac802154_notify(priv, primitive); } @@ -1003,22 +997,17 @@ static void mac802154_txdone_worker(FAR void *arg) break; default: - ieee802154_primitive_free(primitive); break; } } break; default: - { - ieee802154_primitive_free(primitive); - } break; } - /* Free the IOB and the tx descriptor */ + /* Free the tx descriptor with the frame and an unused confirm */ - iob_free(txdesc->frame); mac802154_txdesc_free(priv, txdesc); } diff --git a/wireless/ieee802154/mac802154_assoc.c b/wireless/ieee802154/mac802154_assoc.c index c8cb356925e..52482a6b931 100644 --- a/wireless/ieee802154/mac802154_assoc.c +++ b/wireless/ieee802154/mac802154_assoc.c @@ -442,8 +442,7 @@ void mac802154_txdone_assocreq(FAR struct ieee802154_privmac_s *priv, FAR struct ieee802154_txdesc_s *txdesc) { enum ieee802154_status_e status; - FAR struct ieee802154_primitive_s *primitive = - (FAR struct ieee802154_primitive_s *)txdesc->conf; + FAR struct ieee802154_primitive_s *primitive; if (txdesc->conf->status != IEEE802154_STATUS_SUCCESS) { @@ -459,7 +458,8 @@ void mac802154_txdone_assocreq(FAR struct ieee802154_privmac_s *priv, * why the tx failed from the radio layer. */ - status = txdesc->conf->status; + status = txdesc->conf->status; + primitive = mac802154_txdesc_takeconf(txdesc); primitive->type = IEEE802154_PRIMITIVE_CONF_ASSOC; primitive->u.assocconf.status = status; @@ -546,10 +546,6 @@ void mac802154_txdone_assocreq(FAR struct ieee802154_privmac_s *priv, work_queue(LPWORK, &priv->macop_work, mac802154_extract_assocresp, priv, 0); } - - /* Deallocate the data conf notification as it is no longer needed. */ - - ieee802154_primitive_free(primitive); } } @@ -617,7 +613,7 @@ void mac802154_txdone_datareq_assoc(FAR struct ieee802154_privmac_s *priv, priv->cmd_desc = NULL; nxsem_post(&priv->opsem); - mac802154_notify(priv, primitive); + mac802154_notify(priv, mac802154_txdesc_takeconf(txdesc)); } else { @@ -649,10 +645,6 @@ void mac802154_txdone_datareq_assoc(FAR struct ieee802154_privmac_s *priv, mac802154_timerstart(priv, priv->max_frame_waittime, mac802154_assoctimeout); } - - /* Deallocate the data conf notification as it is no longer needed. */ - - ieee802154_primitive_free(primitive); } } diff --git a/wireless/ieee802154/mac802154_data.c b/wireless/ieee802154/mac802154_data.c index 75d6905500d..bf49b6ac131 100644 --- a/wireless/ieee802154/mac802154_data.c +++ b/wireless/ieee802154/mac802154_data.c @@ -350,7 +350,7 @@ int mac802154_req_data(MACHANDLE mac, errout_with_txdesc: - /* Free TX the descriptor, but preserve the IOB. */ + /* Free the TX descriptor and its confirm, but preserve the IOB */ txdesc->frame = NULL; mac802154_txdesc_free(priv, txdesc); diff --git a/wireless/ieee802154/mac802154_internal.h b/wireless/ieee802154/mac802154_internal.h index e97e6231de3..0656a4775e4 100644 --- a/wireless/ieee802154/mac802154_internal.h +++ b/wireless/ieee802154/mac802154_internal.h @@ -39,6 +39,7 @@ #include <nuttx/wqueue.h> #include <nuttx/mutex.h> #include <nuttx/semaphore.h> +#include <nuttx/mm/iob.h> #include <nuttx/wireless/ieee802154/ieee802154_mac.h> #include <nuttx/wireless/ieee802154/ieee802154_radio.h> @@ -515,10 +516,35 @@ void mac802154_notify(FAR struct ieee802154_privmac_s *priv, /* General helpers **********************************************************/ +/* A tx descriptor owns its frame and its confirm primitive. A user that + * hands the confirm to the next layer takes it out of the descriptor first. + */ + +static inline FAR struct ieee802154_primitive_s * +mac802154_txdesc_takeconf(FAR struct ieee802154_txdesc_s *txdesc) +{ + FAR struct ieee802154_primitive_s *primitive = + (FAR struct ieee802154_primitive_s *)txdesc->conf; + + txdesc->conf = NULL; + return primitive; +} + static inline void mac802154_txdesc_free(FAR struct ieee802154_privmac_s *priv, FAR struct ieee802154_txdesc_s *txdesc) { + if (txdesc->frame != NULL) + { + iob_free(txdesc->frame); + txdesc->frame = NULL; + } + + if (txdesc->conf != NULL) + { + ieee802154_primitive_free(mac802154_txdesc_takeconf(txdesc)); + } + sq_addlast((FAR sq_entry_t *)txdesc, &priv->txdesc_queue); nxsem_post(&priv->txdesc_sem); } diff --git a/wireless/ieee802154/mac802154_poll.c b/wireless/ieee802154/mac802154_poll.c index 57b9acc1d38..f32993601f0 100644 --- a/wireless/ieee802154/mac802154_poll.c +++ b/wireless/ieee802154/mac802154_poll.c @@ -212,7 +212,7 @@ void mac802154_txdone_datareq_poll(FAR struct ieee802154_privmac_s *priv, priv->cmd_desc = NULL; nxsem_post(&priv->opsem); - mac802154_notify(priv, primitive); + mac802154_notify(priv, mac802154_txdesc_takeconf(txdesc)); } else { @@ -231,10 +231,6 @@ void mac802154_txdone_datareq_poll(FAR struct ieee802154_privmac_s *priv, mac802154_timerstart(priv, priv->max_frame_waittime, mac802154_polltimeout); - - /* Deallocate the data conf primitive as it is no longer needed. */ - - ieee802154_primitive_free(primitive); } }
