aboutsummaryrefslogtreecommitdiff
path: root/sys/net80211
diff options
context:
space:
mode:
authorSam Leffler <sam@FreeBSD.org>2007-01-08 18:23:43 +0000
committerSam Leffler <sam@FreeBSD.org>2007-01-08 18:23:43 +0000
commit915f1482a9303e21967e8de2071980116951b93f (patch)
tree16f43e89d59db0da857e97f067440967345c42c3 /sys/net80211
parent70bff0d9b13a6955f32dac6b01e4a85dba213c0b (diff)
downloadsrc-915f1482a9303e21967e8de2071980116951b93f.tar.gz
src-915f1482a9303e21967e8de2071980116951b93f.zip
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
Notes
Notes: svn path=/head/; revision=165894
Diffstat (limited to 'sys/net80211')
-rw-r--r--sys/net80211/ieee80211_freebsd.c20
-rw-r--r--sys/net80211/ieee80211_freebsd.h2
-rw-r--r--sys/net80211/ieee80211_proto.c16
3 files changed, 31 insertions, 7 deletions
diff --git a/sys/net80211/ieee80211_freebsd.c b/sys/net80211/ieee80211_freebsd.c
index 423eab60988c..a44e4c803e87 100644
--- a/sys/net80211/ieee80211_freebsd.c
+++ b/sys/net80211/ieee80211_freebsd.c
@@ -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
diff --git a/sys/net80211/ieee80211_freebsd.h b/sys/net80211/ieee80211_freebsd.h
index 9fc23e507a6f..b555c811dacc 100644
--- a/sys/net80211/ieee80211_freebsd.h
+++ b/sys/net80211/ieee80211_freebsd.h
@@ -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 */
diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c
index 590522f168a8..4fa970b805a4 100644
--- a/sys/net80211/ieee80211_proto.c
+++ b/sys/net80211/ieee80211_proto.c
@@ -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;
+ break;
case IEEE80211_S_AUTH:
- reset:
+ break;
+ }
+ if (ostate != IEEE80211_S_INIT) {
+ /* NB: optimize INIT -> INIT case */
ic->ic_mgt_timer = 0;
- IF_DRAIN(&ic->ic_mgtq);
+ ieee80211_drain_ifq(&ic->ic_mgtq);
ieee80211_reset_bss(ic);
- break;
}
if (ic->ic_auth->ia_detach != NULL)
ic->ic_auth->ia_detach(ic);