From 17b08c4368b5345d26f506dc7aa282df419002eb Mon Sep 17 00:00:00 2001 From: Adrian Chadd Date: Sun, 6 Jan 2013 04:38:31 +0000 Subject: [PATCH] Handle HWMP if_transmit() failure gracefully. If if_transmit() fails, the node ref may need freeing. This is based on the same logic used by the ageq, which the mesh code (re) uses for frames which need to be staged before transmitting. It also does the same thing - if M_ENCAP is set on the mbuf, it treats the recvif pointer as a node reference and derefs it. --- sys/net80211/ieee80211_hwmp.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/sys/net80211/ieee80211_hwmp.c b/sys/net80211/ieee80211_hwmp.c index fcc4af1a66a1..2f8ec851c816 100644 --- a/sys/net80211/ieee80211_hwmp.c +++ b/sys/net80211/ieee80211_hwmp.c @@ -1227,6 +1227,8 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni, struct mbuf *m, *next; uint32_t metric = 0; const uint8_t *addr; + int is_encap; + struct ieee80211_node *ni_encap; if (ni == vap->iv_bss || ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) @@ -1403,11 +1405,21 @@ hwmp_recv_prep(struct ieee80211vap *vap, struct ieee80211_node *ni, (struct ieee80211_node *)(uintptr_t) ieee80211_mac_hash(ic, addr)); /* either dest or ext_dest */ for (; m != NULL; m = next) { + is_encap = !! (m->m_flags & M_ENCAP); + ni_encap = (struct ieee80211_node *) m->m_pkthdr.rcvif; next = m->m_nextpkt; m->m_nextpkt = NULL; IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, ni, "flush queued frame %p len %d", m, m->m_pkthdr.len); - ifp->if_transmit(ifp, m); + + /* + * If the mbuf has M_ENCAP set, ensure we free it. + * Note that after if_transmit() is called, m is invalid. + */ + if (ifp->if_transmit(ifp, m) != 0) { + if (is_encap) + ieee80211_free_node(ni_encap); + } } #undef IS_PROXY #undef PROXIED_BY_US