Fix potential node refcnt leak. If mbufs are q'd on ic_mgtq when

the state machine clocks to INIT, node references are not reclaimed.
Add a new routine ieee80211_drain_ifq that does this and use it
instead of IF_DRAIN.

Submitted by:	Sepherosa Ziehau
Obtained from:	DragonFly
MFC after:	1 month
This commit is contained in:
Sam Leffler 2007-01-08 18:23:43 +00:00
parent 70bff0d9b1
commit 915f1482a9
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=165894
3 changed files with 33 additions and 9 deletions

View File

@ -150,6 +150,26 @@ ieee80211_node_dectestref(struct ieee80211_node *ni)
return atomic_cmpset_int(&ni->ni_refcnt, 0, 1);
}
void
ieee80211_drain_ifq(struct ifqueue *ifq)
{
struct ieee80211_node *ni;
struct mbuf *m;
for (;;) {
IF_DEQUEUE(ifq, m);
if (m == NULL)
break;
ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
KASSERT(ni != NULL, ("frame w/o node"));
ieee80211_free_node(ni);
m->m_pkthdr.rcvif = NULL;
m_freem(m);
}
}
/*
* Allocate and setup a management frame of the specified
* size. We return the mbuf and a pointer to the start

View File

@ -148,6 +148,8 @@ struct ieee80211_node;
int ieee80211_node_dectestref(struct ieee80211_node *ni);
#define ieee80211_node_refcnt(_ni) (_ni)->ni_refcnt
void ieee80211_drain_ifq(struct ifqueue *);
struct mbuf *ieee80211_getmgtframe(u_int8_t **frm, u_int pktlen);
#define M_LINK0 M_PROTO1 /* WEP requested */
#define M_PWR_SAV M_PROTO4 /* bypass PS handling */

View File

@ -129,7 +129,7 @@ ieee80211_proto_detach(struct ieee80211com *ic)
if (ic->ic_auth->ia_detach)
ic->ic_auth->ia_detach(ic);
IF_DRAIN(&ic->ic_mgtq);
ieee80211_drain_ifq(&ic->ic_mgtq);
mtx_destroy(&ic->ic_mgtq.ifq_mtx);
/*
@ -932,7 +932,7 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg
default:
break;
}
goto reset;
break;
case IEEE80211_S_ASSOC:
switch (ic->ic_opmode) {
case IEEE80211_M_STA:
@ -947,16 +947,18 @@ ieee80211_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg
default:
break;
}
goto reset;
break;
case IEEE80211_S_SCAN:
ieee80211_cancel_scan(ic);
goto reset;
case IEEE80211_S_AUTH:
reset:
ic->ic_mgt_timer = 0;
IF_DRAIN(&ic->ic_mgtq);
ieee80211_reset_bss(ic);
break;
case IEEE80211_S_AUTH:
break;
}
if (ostate != IEEE80211_S_INIT) {
/* NB: optimize INIT -> INIT case */
ic->ic_mgt_timer = 0;
ieee80211_drain_ifq(&ic->ic_mgtq);
ieee80211_reset_bss(ic);
}
if (ic->ic_auth->ia_detach != NULL)
ic->ic_auth->ia_detach(ic);