diff options
author | sam <sam@FreeBSD.org> | 2005-07-31 06:12:32 +0000 |
---|---|---|
committer | sam <sam@FreeBSD.org> | 2005-07-31 06:12:32 +0000 |
commit | 2cd7f030b785e55a0de9824d17ef2394f337ec68 (patch) | |
tree | fa9380c5c10353a67a795c544d62f1a273b23f33 /sys | |
parent | e369c14b22814d6dc62b255fd4b6c747159585f0 (diff) | |
download | FreeBSD-src-2cd7f030b785e55a0de9824d17ef2394f337ec68.zip FreeBSD-src-2cd7f030b785e55a0de9824d17ef2394f337ec68.tar.gz |
close a race between reclaiming a node when a station is inactive
and sending the null data frame used to probe inactive stations
MFC after: 5 days
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net80211/ieee80211_input.c | 2 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.c | 8 | ||||
-rw-r--r-- | sys/net80211/ieee80211_output.c | 7 |
3 files changed, 15 insertions, 2 deletions
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c index 38e3db2..e0c4879 100644 --- a/sys/net80211/ieee80211_input.c +++ b/sys/net80211/ieee80211_input.c @@ -2711,7 +2711,7 @@ ieee80211_recv_pspoll(struct ieee80211com *ic, IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER, "[%s] recv ps-poll, but queue empty\n", ether_sprintf(wh->i_addr2)); - ieee80211_send_nulldata(ni); + ieee80211_send_nulldata(ieee80211_ref_node(ni)); ic->ic_stats.is_ps_qempty++; /* XXX node stat */ if (ic->ic_set_tim != NULL) ic->ic_set_tim(ni, 0); /* just in case */ diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c index 81f6138..72884f0 100644 --- a/sys/net80211/ieee80211_node.c +++ b/sys/net80211/ieee80211_node.c @@ -1474,6 +1474,14 @@ IEEE80211_DPRINTF(ic, IEEE80211_MSG_POWER, "[%s] discard frame, age %u\n", ether IEEE80211_MSG_INACT | IEEE80211_MSG_NODE, ni, "%s", "probe station due to inactivity"); + /* + * Grab a reference before unlocking the table + * so the node cannot be reclaimed before we + * send the frame. ieee80211_send_nulldata + * understands we've done this and reclaims the + * ref for us as needed. + */ + ieee80211_ref_node(ni); IEEE80211_NODE_UNLOCK(nt); ieee80211_send_nulldata(ni); /* XXX stat? */ diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c index eb558a5..78b62d0 100644 --- a/sys/net80211/ieee80211_output.c +++ b/sys/net80211/ieee80211_output.c @@ -199,6 +199,10 @@ ieee80211_mgmt_output(struct ieee80211com *ic, struct ieee80211_node *ni, /* * Send a null data frame to the specified node. + * + * NB: the caller is assumed to have setup a node reference + * for use; this is necessary to deal with a race condition + * when probing for inactive stations. */ int ieee80211_send_nulldata(struct ieee80211_node *ni) @@ -212,9 +216,10 @@ ieee80211_send_nulldata(struct ieee80211_node *ni) if (m == NULL) { /* XXX debug msg */ ic->ic_stats.is_tx_nobuf++; + ieee80211_unref_node(&ni); return ENOMEM; } - m->m_pkthdr.rcvif = (void *) ieee80211_ref_node(ni); + m->m_pkthdr.rcvif = (void *) ni; wh = mtod(m, struct ieee80211_frame *); ieee80211_send_setup(ic, ni, wh, |