summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/ath/if_ath.c107
-rw-r--r--sys/dev/ath/if_athvar.h4
-rw-r--r--sys/dev/wi/if_wi.c73
-rw-r--r--sys/net80211/ieee80211_input.c128
-rw-r--r--sys/net80211/ieee80211_node.c33
-rw-r--r--sys/net80211/ieee80211_node.h3
-rw-r--r--sys/net80211/ieee80211_output.c141
-rw-r--r--sys/net80211/ieee80211_proto.h12
-rw-r--r--sys/net80211/ieee80211_var.h3
9 files changed, 310 insertions, 194 deletions
diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c
index ba84f09..fdb0091 100644
--- a/sys/dev/ath/if_ath.c
+++ b/sys/dev/ath/if_ath.c
@@ -691,7 +691,7 @@ ath_start(struct ifnet *ifp)
/*
* Encapsulate the packet in prep for transmission.
*/
- m = ieee80211_encap(ifp, m);
+ m = ieee80211_encap(ifp, m, &ni);
if (m == NULL) {
DPRINTF(("ath_start: encapsulation failure\n"));
sc->sc_stats.ast_tx_encap++;
@@ -701,6 +701,18 @@ ath_start(struct ifnet *ifp)
if (ic->ic_flags & IEEE80211_F_WEPON)
wh->i_fc[1] |= IEEE80211_FC1_WEP;
} else {
+ /*
+ * Hack! The referenced node pointer is in the
+ * rcvif field of the packet header. This is
+ * placed there by ieee80211_mgmt_output because
+ * we need to hold the reference with the frame
+ * and there's no other way (other than packet
+ * tags which we consider too expensive to use)
+ * to pass it along.
+ */
+ ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
+ m->m_pkthdr.rcvif = NULL;
+
wh = mtod(m, struct ieee80211_frame *);
if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
IEEE80211_FC0_SUBTYPE_PROBE_RESP) {
@@ -720,26 +732,6 @@ ath_start(struct ifnet *ifp)
if (ic->ic_rawbpf)
bpf_mtap(ic->ic_rawbpf, m);
- if (ic->ic_opmode != IEEE80211_M_STA) {
- ni = ieee80211_find_node(ic, wh->i_addr1);
- if (ni == NULL) {
- /*
- * When not in station mode the destination
- * address should always be in the node table
- * unless this is a multicast/broadcast frame.
- */
- if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
- (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
- IEEE80211_FC0_TYPE_DATA) {
- m_freem(m);
- sc->sc_stats.ast_tx_nonode++;
- goto bad;
- }
- ni = ic->ic_bss;
- }
- } else
- ni = ic->ic_bss;
-
/*
* TODO:
* The duration field of 802.11 header should be filled.
@@ -759,6 +751,8 @@ ath_start(struct ifnet *ifp)
TAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
mtx_unlock(&sc->sc_txbuflock);
ifp->if_oerrors++;
+ if (ni && ni != ic->ic_bss)
+ ieee80211_free_node(ic, ni);
continue;
}
@@ -1112,12 +1106,13 @@ ath_beacon_proc(void *arg, int pending)
struct ath_hal *ah = sc->sc_ah;
DPRINTF2(("%s: pending %u\n", __func__, pending));
- if (ic->ic_opmode == IEEE80211_M_STA || bf == NULL || bf->bf_m == NULL) {
+ if (ic->ic_opmode == IEEE80211_M_STA ||
+ bf == NULL || bf->bf_m == NULL) {
DPRINTF(("%s: ic_flags=%x bf=%p bf_m=%p\n",
__func__, ic->ic_flags, bf, bf ? bf->bf_m : NULL));
return;
}
- /* update beacon to reflect PS poll state */
+ /* TODO: update beacon to reflect PS poll state */
if (!ath_hal_stoptxdma(ah, sc->sc_bhalq)) {
DPRINTF(("%s: beacon queue %u did not stop?",
__func__, sc->sc_bhalq));
@@ -1371,7 +1366,7 @@ ath_node_alloc(struct ieee80211com *ic)
{
struct ath_node *an =
malloc(sizeof(struct ath_node), M_DEVBUF, M_NOWAIT | M_ZERO);
- return an ? &an->st_node : NULL;
+ return an ? &an->an_node : NULL;
}
static void
@@ -1461,6 +1456,7 @@ ath_rx_proc(void *arg, int npending)
struct ath_desc *ds;
struct mbuf *m;
struct ieee80211_frame *wh, whbuf;
+ struct ieee80211_node *ni;
int len;
u_int phyerr;
HAL_STATUS status;
@@ -1505,6 +1501,7 @@ ath_rx_proc(void *arg, int npending)
len = ds->ds_rxstat.rs_datalen;
if (len < sizeof(struct ieee80211_frame)) {
DPRINTF(("ath_rx_proc: short packet %d\n", len));
+ sc->sc_stats.ast_rx_tooshort++;
goto rx_next;
}
@@ -1516,7 +1513,7 @@ ath_rx_proc(void *arg, int npending)
IEEE80211_FC0_TYPE_CTL &&
ic->ic_opmode != IEEE80211_M_MONITOR) {
/*
- * Ignore control frame received in promisc mode.
+ * Discard control frame when not in monitor mode.
*/
DPRINTF(("ath_rx_proc: control frame\n"));
sc->sc_stats.ast_rx_ctl++;
@@ -1533,6 +1530,7 @@ ath_rx_proc(void *arg, int npending)
IEEE80211_RATE_VAL,
ds->ds_rxstat.rs_rssi);
}
+
m_adj(m, -IEEE80211_CRC_LEN);
if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
/*
@@ -1548,10 +1546,35 @@ ath_rx_proc(void *arg, int npending)
*/
m_adj(m, -IEEE80211_WEP_CRCLEN);
}
- ieee80211_input(ifp, m,
- ds->ds_rxstat.rs_rssi,
- ds->ds_rxstat.rs_tstamp,
- ds->ds_rxstat.rs_antenna);
+
+ /*
+ * Locate the node for sender, track state, and
+ * then pass this node (referenced) up to the 802.11
+ * layer for its use. We are required to pass
+ * something so we fall back to ic_bss when this frame
+ * is from an unknown sender.
+ */
+ if (ic->ic_opmode != IEEE80211_M_STA) {
+ ni = ieee80211_find_node(ic, wh->i_addr2);
+ if (ni == NULL)
+ ni = ieee80211_ref_node(ic->ic_bss);
+ } else
+ ni = ieee80211_ref_node(ic->ic_bss);
+ ATH_NODE(ni)->an_rx_antenna = ds->ds_rxstat.rs_antenna;
+ /*
+ * Send frame up for processing.
+ */
+ ieee80211_input(ifp, m, ni,
+ ds->ds_rxstat.rs_rssi, ds->ds_rxstat.rs_tstamp);
+ /*
+ * The frame may have caused the node to be marked for
+ * reclamation (e.g. in response to a DEAUTH message)
+ * so use free_node here instead of unref_node.
+ */
+ if (ni == ic->ic_bss)
+ ieee80211_unref_node(&ni);
+ else
+ ieee80211_free_node(ic, ni);
rx_next:
TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
} while (ath_rxbuf_init(sc, bf) == 0);
@@ -1681,7 +1704,7 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
DPRINTF2(("ath_tx_start: m %p len %u\n", m0, pktlen));
bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap, BUS_DMASYNC_PREWRITE);
bf->bf_m = m0;
- bf->bf_node = ni;
+ bf->bf_node = ni; /* NB: held reference */
/* setup descriptors */
ds = bf->bf_desc;
@@ -1792,7 +1815,7 @@ ath_tx_start(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_buf *bf
if (an->an_tx_antenna)
antenna = an->an_tx_antenna;
else
- antenna = ni->ni_rantenna;
+ antenna = an->an_rx_antenna;
/*
* Formulate first tx descriptor with tx controls.
@@ -1865,7 +1888,8 @@ ath_tx_proc(void *arg, int npending)
struct ath_softc *sc = arg;
struct ath_hal *ah = sc->sc_ah;
struct ath_buf *bf;
- struct ifnet *ifp = &sc->sc_ic.ic_if;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &ic->ic_if;
struct ath_desc *ds;
struct ieee80211_node *ni;
struct ath_node *an;
@@ -1920,6 +1944,15 @@ ath_tx_proc(void *arg, int npending)
sc->sc_stats.ast_tx_longretry += lr;
if (sr + lr)
an->an_tx_retr++;
+ /*
+ * Reclaim reference to node.
+ *
+ * NB: the node may be reclaimed here if, for example
+ * this is a DEAUTH message that was sent and the
+ * node was timed out due to inactivity.
+ */
+ if (ni != ic->ic_bss)
+ ieee80211_free_node(ic, ni);
}
bus_dmamap_sync(sc->sc_dmat, bf->bf_dmamap,
BUS_DMASYNC_POSTWRITE);
@@ -2093,11 +2126,6 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan)
}
/*
- * Re-enable interrupts.
- */
- ath_hal_intrset(ah, sc->sc_imask);
-
- /*
* Change channels and update the h/w rate map
* if we're switching; e.g. 11a to 11b/g.
*/
@@ -2105,6 +2133,11 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan)
mode = ieee80211_chan2mode(ic, chan);
if (mode != sc->sc_curmode)
ath_setcurmode(sc, mode);
+
+ /*
+ * Re-enable interrupts.
+ */
+ ath_hal_intrset(ah, sc->sc_imask);
}
return 0;
}
diff --git a/sys/dev/ath/if_athvar.h b/sys/dev/ath/if_athvar.h
index dac204a..378a0ba 100644
--- a/sys/dev/ath/if_athvar.h
+++ b/sys/dev/ath/if_athvar.h
@@ -55,13 +55,15 @@
/* driver-specific node */
struct ath_node {
- struct ieee80211_node st_node; /* base class */
+ struct ieee80211_node an_node; /* base class */
u_int an_tx_ok; /* tx ok pkt */
u_int an_tx_err; /* tx !ok pkt */
u_int an_tx_retr; /* tx retry count */
int an_tx_upper; /* tx upper rate req cnt */
u_int an_tx_antenna; /* antenna for last good frame */
+ u_int an_rx_antenna; /* antenna for last rcvd frame */
};
+#define ATH_NODE(_n) ((struct ath_node *)(_n))
struct ath_buf {
TAILQ_ENTRY(ath_buf) bf_list;
diff --git a/sys/dev/wi/if_wi.c b/sys/dev/wi/if_wi.c
index 91e68b1..2fd33d5 100644
--- a/sys/dev/wi/if_wi.c
+++ b/sys/dev/wi/if_wi.c
@@ -805,10 +805,11 @@ wi_start(struct ifnet *ifp)
{
struct wi_softc *sc = ifp->if_softc;
struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211_node *ni;
struct ieee80211_frame *wh;
struct mbuf *m0;
struct wi_frame frmhdr;
- int cur, fid, off;
+ int cur, fid, off, error;
WI_LOCK_DECL();
WI_LOCK(sc);
@@ -832,6 +833,18 @@ wi_start(struct ifnet *ifp)
break;
}
IF_DEQUEUE(&ic->ic_mgtq, m0);
+ /*
+ * Hack! The referenced node pointer is in the
+ * rcvif field of the packet header. This is
+ * placed there by ieee80211_mgmt_output because
+ * we need to hold the reference with the frame
+ * and there's no other way (other than packet
+ * tags which we consider too expensive to use)
+ * to pass it along.
+ */
+ ni = (struct ieee80211_node *) m0->m_pkthdr.rcvif;
+ m0->m_pkthdr.rcvif = NULL;
+
m_copydata(m0, 4, ETHER_ADDR_LEN * 2,
(caddr_t)&frmhdr.wi_ehdr);
frmhdr.wi_ehdr.ether_type = 0;
@@ -854,26 +867,12 @@ wi_start(struct ifnet *ifp)
BPF_MTAP(ifp, m0);
#endif
- if ((m0 = ieee80211_encap(ifp, m0)) == NULL) {
+ m0 = ieee80211_encap(ifp, m0, &ni);
+ if (m0 == NULL) {
ifp->if_oerrors++;
continue;
}
wh = mtod(m0, struct ieee80211_frame *);
- if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
- !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
- (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
- IEEE80211_FC0_TYPE_DATA) {
- struct ieee80211_node *ni =
- ieee80211_find_node(ic, wh->i_addr1);
- int err = (ni == NULL || ni->ni_associd == 0);
- if (ni != NULL)
- ieee80211_unref_node(&ni);
- if (err) {
- m_freem(m0);
- ifp->if_oerrors++;
- continue;
- }
- }
if (ic->ic_flags & IEEE80211_F_WEPON)
wh->i_fc[1] |= IEEE80211_FC1_WEP;
@@ -887,6 +886,8 @@ wi_start(struct ifnet *ifp)
(wh->i_fc[1] & IEEE80211_FC1_WEP)) {
if ((m0 = ieee80211_wep_crypt(ifp, m0, 1)) == NULL) {
ifp->if_oerrors++;
+ if (ni && ni != ic->ic_bss)
+ ieee80211_free_node(ic, ni);
continue;
}
frmhdr.wi_tx_ctl |= htole16(WI_TXCNTL_NOCRYPT);
@@ -915,13 +916,15 @@ wi_start(struct ifnet *ifp)
wi_dump_pkt(&frmhdr, NULL, -1);
fid = sc->sc_txd[cur].d_fid;
off = sizeof(frmhdr);
- if (wi_write_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0 ||
- wi_mwrite_bap(sc, fid, off, m0, m0->m_pkthdr.len) != 0) {
+ error = wi_write_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0
+ || wi_mwrite_bap(sc, fid, off, m0, m0->m_pkthdr.len) != 0;
+ m_freem(m0);
+ if (ni && ni != ic->ic_bss)
+ ieee80211_free_node(ic, ni);
+ if (error) {
ifp->if_oerrors++;
- m_freem(m0);
continue;
}
- m_freem(m0);
sc->sc_txd[cur].d_len = off;
if (sc->sc_txcur == cur) {
if (wi_cmd(sc, WI_CMD_TX | WI_RECLAIM, fid, 0, 0)) {
@@ -1355,6 +1358,7 @@ wi_rx_intr(struct wi_softc *sc)
struct wi_frame frmhdr;
struct mbuf *m;
struct ieee80211_frame *wh;
+ struct ieee80211_node *ni;
int fid, len, off, rssi;
u_int8_t dir;
u_int16_t status;
@@ -1471,7 +1475,32 @@ wi_rx_intr(struct wi_softc *sc)
if (ic->ic_opmode == IEEE80211_M_IBSS && dir == IEEE80211_FC1_DIR_NODS)
wi_sync_bssid(sc, wh->i_addr3);
- ieee80211_input(ifp, m, rssi, rstamp, 0);
+ /*
+ * Locate the node for sender, track state, and
+ * then pass this node (referenced) up to the 802.11
+ * layer for its use. We are required to pass
+ * something so we fallback to ic_bss when this frame
+ * is from an unknown sender.
+ */
+ if (ic->ic_opmode != IEEE80211_M_STA) {
+ ni = ieee80211_find_node(ic, wh->i_addr2);
+ if (ni == NULL)
+ ni = ieee80211_ref_node(ic->ic_bss);
+ } else
+ ni = ieee80211_ref_node(ic->ic_bss);
+ /*
+ * Send frame up for processing.
+ */
+ ieee80211_input(ifp, m, ni, rssi, rstamp);
+ /*
+ * The frame may have caused the node to be marked for
+ * reclamation (e.g. in response to a DEAUTH message)
+ * so use free_node here instead of unref_node.
+ */
+ if (ni == ic->ic_bss)
+ ieee80211_unref_node(&ni);
+ else
+ ieee80211_free_node(ic, ni);
}
static void
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c
index 542d455..003b425 100644
--- a/sys/net80211/ieee80211_input.c
+++ b/sys/net80211/ieee80211_input.c
@@ -66,12 +66,21 @@ __FBSDID("$FreeBSD$");
#include <netinet/if_ether.h>
#endif
+/*
+ * Process a received frame. The node associated with the sender
+ * should be supplied. If nothing was found in the node table then
+ * the caller is assumed to supply a reference to ic_bss instead.
+ * The RSSI and a timestamp are also supplied. The RSSI data is used
+ * during AP scanning to select a AP to associate with; it can have
+ * any units so long as values have consistent units and higher values
+ * mean ``better signal''. The receive timestamp is currently not used
+ * by the 802.11 layer.
+ */
void
-ieee80211_input(struct ifnet *ifp, struct mbuf *m,
- int rssi, u_int32_t rstamp, u_int rantenna)
+ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
+ int rssi, u_int32_t rstamp)
{
struct ieee80211com *ic = (void *)ifp;
- struct ieee80211_node *ni = NULL;
struct ieee80211_frame *wh;
struct ether_header *eh;
struct mbuf *m1;
@@ -80,6 +89,8 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m,
u_int8_t *bssid;
u_int16_t rxseq;
+ KASSERT(ni != NULL, ("null node"));
+
/* trim CRC here for WEP can find its own CRC at the end of packet. */
if (m->m_flags & M_HASFCS) {
m_adj(m, -IEEE80211_CRC_LEN);
@@ -92,6 +103,7 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m,
if (ifp->if_flags & IFF_DEBUG)
if_printf(ifp, "receive packet with wrong version: %x\n",
wh->i_fc[0]);
+ ieee80211_unref_node(&ni);
goto err;
}
@@ -100,13 +112,11 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m,
if (ic->ic_state != IEEE80211_S_SCAN) {
switch (ic->ic_opmode) {
case IEEE80211_M_STA:
- ni = ieee80211_ref_node(ic->ic_bss);
if (!IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid)) {
IEEE80211_DPRINTF2(("%s: discard frame from "
"bss %s\n", __func__,
ether_sprintf(wh->i_addr2)));
/* not interested in */
- ieee80211_unref_node(&ni);
goto out;
}
break;
@@ -124,19 +134,6 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m,
__func__, ether_sprintf(wh->i_addr3)));
goto out;
}
- ni = ieee80211_find_node(ic, wh->i_addr2);
- if (ni == NULL) {
- IEEE80211_DPRINTF2(("%s: warning, unknown src "
- "%s\n", __func__,
- ether_sprintf(wh->i_addr2)));
- /*
- * NB: Node allocation is handled in the
- * management handling routines. Just fake
- * up a reference to the hosts's node to do
- * the stuff below.
- */
- ni = ieee80211_ref_node(ic->ic_bss);
- }
break;
case IEEE80211_M_MONITOR:
/* NB: this should collect everything */
@@ -147,7 +144,6 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m,
}
ni->ni_rssi = rssi;
ni->ni_rstamp = rstamp;
- ni->ni_rantenna = rantenna;
rxseq = ni->ni_rxseq;
ni->ni_rxseq =
le16toh(*(u_int16_t *)wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT;
@@ -155,11 +151,9 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m,
if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
rxseq == ni->ni_rxseq) {
/* duplicate, silently discarded */
- ieee80211_unref_node(&ni);
goto out;
}
ni->ni_inact = 0;
- ieee80211_unref_node(&ni);
}
switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
@@ -189,11 +183,11 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m,
if (dir != IEEE80211_FC1_DIR_TODS)
goto out;
/* check if source STA is associated */
- ni = ieee80211_find_node(ic, wh->i_addr2);
- if (ni == NULL) {
+ if (ni == ic->ic_bss) {
IEEE80211_DPRINTF(("%s: data from unknown src "
"%s\n", __func__,
ether_sprintf(wh->i_addr2)));
+ /* NB: caller deals with reference */
ni = ieee80211_dup_bss(ic, wh->i_addr2);
if (ni != NULL) {
IEEE80211_SEND_MGMT(ic, ni,
@@ -213,7 +207,6 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m,
ieee80211_unref_node(&ni);
goto err;
}
- ieee80211_unref_node(&ni);
break;
case IEEE80211_M_MONITOR:
break;
@@ -240,7 +233,7 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m,
if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
eh = mtod(m, struct ether_header *);
if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
- m1 = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
+ m1 = m_copypacket(m, M_DONTWAIT);
if (m1 == NULL)
ifp->if_oerrors++;
else
@@ -318,7 +311,7 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m,
}
if (ic->ic_rawbpf)
bpf_mtap(ic->ic_rawbpf, m);
- (*ic->ic_recv_mgmt)(ic, m, subtype, rssi, rstamp, rantenna);
+ (*ic->ic_recv_mgmt)(ic, m, ni, subtype, rssi, rstamp);
m_freem(m);
return;
@@ -499,13 +492,13 @@ ieee80211_setup_rates(struct ieee80211com *ic, struct ieee80211_node *ni,
} while (0)
void
-ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, int subtype,
- int rssi, u_int32_t rstamp, u_int rantenna)
+ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
+ struct ieee80211_node *ni,
+ int subtype, int rssi, u_int32_t rstamp)
{
#define ISPROBE(_st) ((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
struct ifnet *ifp = &ic->ic_if;
struct ieee80211_frame *wh;
- struct ieee80211_node *ni;
u_int8_t *frm, *efrm;
u_int8_t *ssid, *rates, *xrates;
int reassoc, resp, newassoc, allocbs;
@@ -672,7 +665,6 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, int subtype,
IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3);
ni->ni_rssi = rssi;
ni->ni_rstamp = rstamp;
- ni->ni_rantenna = rantenna;
memcpy(ni->ni_tstamp, tstamp, sizeof(ni->ni_tstamp));
ni->ni_intval = le16toh(*(u_int16_t *)bintval);
ni->ni_capinfo = le16toh(*(u_int16_t *)capinfo);
@@ -731,8 +723,7 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, int subtype,
return;
}
- ni = ieee80211_find_node(ic, wh->i_addr2);
- if (ni == NULL) {
+ if (ni == ic->ic_bss) {
ni = ieee80211_dup_bss(ic, wh->i_addr2);
if (ni == NULL)
return;
@@ -743,7 +734,6 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, int subtype,
allocbs = 0;
ni->ni_rssi = rssi;
ni->ni_rstamp = rstamp;
- ni->ni_rantenna = rantenna;
rate = ieee80211_setup_rates(ic, ni, rates, xrates,
IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE
| IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
@@ -751,13 +741,16 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, int subtype,
IEEE80211_DPRINTF(("%s: rate negotiation failed: %s\n",
__func__,ether_sprintf(wh->i_addr2)));
} else {
- IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_PROBE_RESP,
- 0);
+ IEEE80211_SEND_MGMT(ic, ni,
+ IEEE80211_FC0_SUBTYPE_PROBE_RESP, 0);
+ }
+ if (allocbs) {
+ /* XXX just use free? */
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP)
+ ieee80211_free_node(ic, ni);
+ else
+ ieee80211_unref_node(&ni);
}
- if (allocbs && ic->ic_opmode == IEEE80211_M_HOSTAP)
- ieee80211_free_node(ic, ni);
- else
- ieee80211_unref_node(&ni);
break;
}
@@ -795,25 +788,23 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, int subtype,
case IEEE80211_M_HOSTAP:
if (ic->ic_state != IEEE80211_S_RUN || seq != 1)
return;
- allocbs = 0;
- ni = ieee80211_find_node(ic, wh->i_addr2);
- if (ni == NULL) {
+ if (ni == ic->ic_bss) {
ni = ieee80211_alloc_node(ic, wh->i_addr2);
if (ni == NULL)
return;
IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid);
ni->ni_rssi = rssi;
ni->ni_rstamp = rstamp;
- ni->ni_rantenna = rantenna;
ni->ni_chan = ic->ic_bss->ni_chan;
allocbs = 1;
- }
- IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_AUTH, 2);
+ } else
+ allocbs = 0;
+ IEEE80211_SEND_MGMT(ic, ni,
+ IEEE80211_FC0_SUBTYPE_AUTH, 2);
if (ifp->if_flags & IFF_DEBUG)
if_printf(ifp, "station %s %s authenticated\n",
(allocbs ? "newly" : "already"),
ether_sprintf(ni->ni_macaddr));
- ieee80211_unref_node(&ni);
break;
case IEEE80211_M_STA:
@@ -824,11 +815,8 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, int subtype,
"authentication failed (reason %d) for %s\n",
status,
ether_sprintf(wh->i_addr3));
- ni = ieee80211_find_node(ic, wh->i_addr2);
- if (ni != NULL) {
+ if (ni != ic->ic_bss)
ni->ni_fails++;
- ieee80211_unref_node(&ni);
- }
return;
}
ieee80211_new_state(ic, IEEE80211_S_ASSOC,
@@ -902,16 +890,16 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, int subtype,
#endif
return;
}
- ni = ieee80211_find_node(ic, wh->i_addr2);
- if (ni == NULL) {
+ if (ni == ic->ic_bss) {
IEEE80211_DPRINTF(("%s: not authenticated for %s\n",
__func__, ether_sprintf(wh->i_addr2)));
ni = ieee80211_dup_bss(ic, wh->i_addr2);
- if (ni == NULL)
- return;
- IEEE80211_SEND_MGMT(ic, ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
- IEEE80211_REASON_ASSOC_NOT_AUTHED);
- ieee80211_free_node(ic, ni);
+ if (ni != NULL) {
+ IEEE80211_SEND_MGMT(ic, ni,
+ IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_ASSOC_NOT_AUTHED);
+ ieee80211_free_node(ic, ni);
+ }
return;
}
/* XXX per-node cipher suite */
@@ -924,8 +912,8 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, int subtype,
IEEE80211_DPRINTF(("%s: capability mismatch %x for %s\n",
__func__, capinfo, ether_sprintf(wh->i_addr2)));
ni->ni_associd = 0;
- IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_CAPINFO);
- ieee80211_unref_node(&ni);
+ IEEE80211_SEND_MGMT(ic, ni, resp,
+ IEEE80211_STATUS_CAPINFO);
return;
}
ieee80211_setup_rates(ic, ni, rates, xrates,
@@ -935,13 +923,12 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, int subtype,
IEEE80211_DPRINTF(("%s: rate unmatch for %s\n",
__func__, ether_sprintf(wh->i_addr2)));
ni->ni_associd = 0;
- IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_BASIC_RATE);
- ieee80211_unref_node(&ni);
+ IEEE80211_SEND_MGMT(ic, ni, resp,
+ IEEE80211_STATUS_BASIC_RATE);
return;
}
ni->ni_rssi = rssi;
ni->ni_rstamp = rstamp;
- ni->ni_rantenna = rantenna;
ni->ni_intval = bintval;
ni->ni_capinfo = capinfo;
ni->ni_chan = ic->ic_bss->ni_chan;
@@ -964,7 +951,6 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, int subtype,
/* give driver a chance to setup state like ni_txrate */
if (ic->ic_newassoc)
(*ic->ic_newassoc)(ic, ni, newassoc);
- ieee80211_unref_node(&ni);
break;
}
@@ -994,11 +980,8 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, int subtype,
if (status != 0) {
if_printf(ifp, "association failed (reason %d) for %s\n",
status, ether_sprintf(wh->i_addr3));
- ni = ieee80211_find_node(ic, wh->i_addr2);
- if (ni != NULL) {
+ if (ni != ic->ic_bss)
ni->ni_fails++;
- ieee80211_unref_node(&ni);
- }
return;
}
ni->ni_associd = le16toh(*(u_int16_t *)frm);
@@ -1041,13 +1024,13 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, int subtype,
wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
break;
case IEEE80211_M_HOSTAP:
- ni = ieee80211_find_node(ic, wh->i_addr2);
- if (ni != NULL) {
+ if (ni != ic->ic_bss) {
if (ifp->if_flags & IFF_DEBUG)
if_printf(ifp, "station %s deauthenticated"
" by peer (reason %d)\n",
ether_sprintf(ni->ni_macaddr), reason);
- ieee80211_free_node(ic, ni);
+ /* node will be free'd on return */
+ ieee80211_unref_node(&ni);
}
break;
default:
@@ -1070,14 +1053,13 @@ ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0, int subtype,
wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
break;
case IEEE80211_M_HOSTAP:
- ni = ieee80211_find_node(ic, wh->i_addr2);
- if (ni != NULL) {
+ if (ni != ic->ic_bss) {
if (ifp->if_flags & IFF_DEBUG)
if_printf(ifp, "station %s disassociated"
" by peer (reason %d)\n",
ether_sprintf(ni->ni_macaddr), reason);
ni->ni_associd = 0;
- ieee80211_unref_node(&ni);
+ /* XXX node reclaimed how? */
}
break;
default:
diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c
index dd2541e..5ea3466 100644
--- a/sys/net80211/ieee80211_node.c
+++ b/sys/net80211/ieee80211_node.c
@@ -216,7 +216,6 @@ ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan)
memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen);
ni->ni_rssi = 0;
ni->ni_rstamp = 0;
- ni->ni_rantenna = 0;
memset(ni->ni_tstamp, 0, sizeof(ni->ni_tstamp));
ni->ni_intval = ic->ic_lintval;
ni->ni_capinfo = IEEE80211_CAPINFO_IBSS;
@@ -289,7 +288,7 @@ ieee80211_end_scan(struct ifnet *ifp)
}
selbs = NULL;
if (ifp->if_flags & IFF_DEBUG)
- if_printf(ifp, "\tmacaddr bssid chan rssi rate ant flag wep essid\n");
+ if_printf(ifp, "\tmacaddr bssid chan rssi rate flag wep essid\n");
for (; ni != NULL; ni = nextbs) {
ieee80211_ref_node(ni);
nextbs = TAILQ_NEXT(ni, ni_list);
@@ -344,7 +343,6 @@ ieee80211_end_scan(struct ifnet *ifp)
printf(" %+4d", ni->ni_rssi);
printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2,
fail & 0x08 ? '!' : ' ');
- printf(" %3d", ni->ni_rantenna);
printf(" %4s%c",
(ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" :
(ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" :
@@ -497,6 +495,8 @@ ieee80211_lookup_node(struct ieee80211com *ic,
static void
_ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni)
{
+ KASSERT(ni != ic->ic_bss, ("freeing bss node"));
+
TAILQ_REMOVE(&ic->ic_node, ni, ni_list);
LIST_REMOVE(ni, ni_hash);
if (TAILQ_EMPTY(&ic->ic_node))
@@ -507,6 +507,8 @@ _ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni)
void
ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni)
{
+ KASSERT(ni != ic->ic_bss, ("freeing ic_bss"));
+
/* XXX need equivalent of atomic_dec_and_test */
atomic_subtract_int(&ni->ni_refcnt, 1);
if (atomic_cmpset_int(&ni->ni_refcnt, 0, 1)) {
@@ -534,21 +536,22 @@ ieee80211_timeout_nodes(struct ieee80211com *ic)
mtx_lock(&ic->ic_nodelock);
for (ni = TAILQ_FIRST(&ic->ic_node); ni != NULL;) {
- if (++ni->ni_inact <= IEEE80211_INACT_MAX) {
- ni = TAILQ_NEXT(ni, ni_list);
- continue;
- }
- /* NB: don't honor reference count */
- IEEE80211_DPRINTF(("station %s timed out "
+ if (++ni->ni_inact > IEEE80211_INACT_MAX) {
+ IEEE80211_DPRINTF(("station %s timed out "
"due to inactivity (%u secs)\n",
ether_sprintf(ni->ni_macaddr),
ni->ni_inact));
- nextbs = TAILQ_NEXT(ni, ni_list);
- IEEE80211_SEND_MGMT(ic, ni,
- IEEE80211_FC0_SUBTYPE_DEAUTH,
- IEEE80211_REASON_AUTH_EXPIRE);
- _ieee80211_free_node(ic, ni);
- ni = nextbs;
+ nextbs = TAILQ_NEXT(ni, ni_list);
+ /*
+ * Send a deauthenticate frame.
+ */
+ IEEE80211_SEND_MGMT(ic, ni,
+ IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_AUTH_EXPIRE);
+ ieee80211_free_node(ic, ni);
+ ni = nextbs;
+ } else
+ ni = TAILQ_NEXT(ni, ni_list);
}
if (!TAILQ_EMPTY(&ic->ic_node))
ic->ic_inact_timer = IEEE80211_INACT_WAIT;
diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h
index d4d62de..de300fa 100644
--- a/sys/net80211/ieee80211_node.h
+++ b/sys/net80211/ieee80211_node.h
@@ -64,9 +64,8 @@ struct ieee80211_node {
u_int ni_refcnt;
/* hardware */
- u_int8_t ni_rssi; /* recv ssi */
u_int32_t ni_rstamp; /* recv timestamp */
- u_int8_t ni_rantenna; /* recv antenna */
+ u_int8_t ni_rssi; /* recv ssi */
/* header */
u_int8_t ni_macaddr[IEEE80211_ADDR_LEN];
diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c
index 9b79d65..1fa87f2 100644
--- a/sys/net80211/ieee80211_output.c
+++ b/sys/net80211/ieee80211_output.c
@@ -66,20 +66,41 @@ __FBSDID("$FreeBSD$");
#include <netinet/if_ether.h>
#endif
-int
+/*
+ * Send a management frame to the specified node. The node pointer
+ * must have a reference as the pointer will be passed to the driver
+ * and potentially held for a long time. If the frame is successfully
+ * dispatched to the driver, then it is responsible for freeing the
+ * reference (and potentially free'ing up any associated storage).
+ */
+static int
ieee80211_mgmt_output(struct ifnet *ifp, struct ieee80211_node *ni,
struct mbuf *m, int type)
{
struct ieee80211com *ic = (void *)ifp;
struct ieee80211_frame *wh;
- /* XXX this probably shouldn't be permitted */
- KASSERT(ni != NULL, ("%s: null node", __func__));
+ KASSERT(ni != NULL, ("null node"));
ni->ni_inact = 0;
+ /*
+ * Yech, hack alert! We want to pass the node down to the
+ * driver's start routine. If we don't do so then the start
+ * routine must immediately look it up again and that can
+ * cause a lock order reversal if, for example, this frame
+ * is being sent because the station is being timedout and
+ * the frame being sent is a DEAUTH message. We could stick
+ * this in an m_tag and tack that on to the mbuf. However
+ * that's rather expensive to do for every frame so instead
+ * we stuff it in the rcvif field since outbound frames do
+ * not (presently) use this.
+ */
M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
if (m == NULL)
return ENOMEM;
+ KASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null"));
+ m->m_pkthdr.rcvif = (void *)ni;
+
wh = mtod(m, struct ieee80211_frame *);
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | type;
wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
@@ -106,31 +127,57 @@ ieee80211_mgmt_output(struct ifnet *ifp, struct ieee80211_node *ni,
ether_sprintf(ni->ni_macaddr),
ieee80211_chan2ieee(ic, ni->ni_chan));
}
+
IF_ENQUEUE(&ic->ic_mgtq, m);
ifp->if_timer = 1;
(*ifp->if_start)(ifp);
return 0;
}
+/*
+ * Encapsulate an outbound data frame. The mbuf chain is updated and
+ * a reference to the destination node is returned. If an error is
+ * encountered NULL is returned and the node reference will also be NULL.
+ *
+ * NB: The caller is responsible for free'ing a returned node reference.
+ * The convention is ic_bss is not reference counted; the caller must
+ * maintain that.
+ */
struct mbuf *
-ieee80211_encap(struct ifnet *ifp, struct mbuf *m)
+ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni)
{
struct ieee80211com *ic = (void *)ifp;
struct ether_header eh;
struct ieee80211_frame *wh;
+ struct ieee80211_node *ni = NULL;
struct llc *llc;
- struct ieee80211_node *ni;
if (m->m_len < sizeof(struct ether_header)) {
m = m_pullup(m, sizeof(struct ether_header));
- if (m == NULL)
- return NULL;
+ if (m == NULL) {
+ /* XXX statistic */
+ goto bad;
+ }
}
memcpy(&eh, mtod(m, caddr_t), sizeof(struct ether_header));
- ni = ieee80211_find_node(ic, eh.ether_dhost);
- if (ni == NULL) /*ic_opmode?? XXX*/
- ni = ieee80211_ref_node(ic->ic_bss);
+ if (ic->ic_opmode != IEEE80211_M_STA) {
+ ni = ieee80211_find_node(ic, eh.ether_dhost);
+ if (ni == NULL) {
+ /*
+ * When not in station mode the
+ * destination address should always be
+ * in the node table unless this is a
+ * multicast/broadcast frame.
+ */
+ if (!IEEE80211_IS_MULTICAST(eh.ether_dhost)) {
+ /* ic->ic_stats.st_tx_nonode++; XXX statistic */
+ goto bad;
+ }
+ ni = ic->ic_bss;
+ }
+ } else
+ ni = ic->ic_bss;
ni->ni_inact = 0;
m_adj(m, sizeof(struct ether_header) - sizeof(struct llc));
@@ -142,10 +189,8 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m)
llc->llc_snap.org_code[2] = 0;
llc->llc_snap.ether_type = eh.ether_type;
M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
- if (m == NULL) {
- ieee80211_unref_node(&ni);
- return NULL;
- }
+ if (m == NULL)
+ goto bad;
wh = mtod(m, struct ieee80211_frame *);
wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
*(u_int16_t *)wh->i_dur = 0;
@@ -173,11 +218,17 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m)
IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost);
break;
case IEEE80211_M_MONITOR:
- m_freem(m), m = NULL;
- break;
+ goto bad;
}
- ieee80211_unref_node(&ni);
+ *pni = ni;
return m;
+bad:
+ if (m != NULL)
+ m_freem(m);
+ if (ni && ni != ic->ic_bss)
+ ieee80211_free_node(ic, ni);
+ *pni = NULL;
+ return NULL;
}
/*
@@ -240,10 +291,16 @@ ieee80211_getmbuf(int flags, int type, u_int pktlen)
return m;
}
+/*
+ * Send a management frame. The node is for the destination (or ic_bss
+ * when in station mode). Nodes other than ic_bss have their reference
+ * count bumped to reflect our use for an indeterminant time.
+ */
int
ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
int type, int arg)
{
+#define senderr(_x) do { ret = _x; goto bad; } while (0)
struct ifnet *ifp = &ic->ic_if;
struct mbuf *m;
u_int8_t *frm;
@@ -251,6 +308,15 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
u_int16_t capinfo;
int ret, timer;
+ KASSERT(ni != NULL, ("null node"));
+
+ /*
+ * Hold a reference on the node so it doesn't go away until after
+ * the xmit is complete all the way in the driver. On error we
+ * will remove our reference.
+ */
+ if (ni != ic->ic_bss)
+ ieee80211_ref_node(ni);
timer = 0;
switch (type) {
case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
@@ -265,7 +331,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
+ 2 + IEEE80211_RATE_SIZE
+ 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
if (m == NULL)
- return ENOMEM;
+ senderr(ENOMEM);
m->m_data += sizeof(struct ieee80211_frame);
frm = mtod(m, u_int8_t *);
frm = ieee80211_add_ssid(frm, ic->ic_des_essid, ic->ic_des_esslen);
@@ -295,7 +361,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
+ 6
+ 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
if (m == NULL)
- return ENOMEM;
+ senderr(ENOMEM);
m->m_data += sizeof(struct ieee80211_frame);
frm = mtod(m, u_int8_t *);
@@ -336,7 +402,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
case IEEE80211_FC0_SUBTYPE_AUTH:
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL)
- return ENOMEM;
+ senderr(ENOMEM);
MH_ALIGN(m, 2 * 3);
m->m_pkthdr.len = m->m_len = 6;
frm = mtod(m, u_int8_t *);
@@ -354,7 +420,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
ether_sprintf(ni->ni_macaddr), arg);
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL)
- return ENOMEM;
+ senderr(ENOMEM);
MH_ALIGN(m, 2);
m->m_pkthdr.len = m->m_len = 2;
*mtod(m, u_int16_t *) = htole16(arg); /* reason */
@@ -379,7 +445,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
+ 2 + IEEE80211_RATE_SIZE
+ 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
if (m == NULL)
- return ENOMEM;
+ senderr(ENOMEM);
m->m_data += sizeof(struct ieee80211_frame);
frm = mtod(m, u_int8_t *);
@@ -430,7 +496,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
+ 2 + IEEE80211_RATE_SIZE
+ 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
if (m == NULL)
- return ENOMEM;
+ senderr(ENOMEM);
m->m_data += sizeof(struct ieee80211_frame);
frm = mtod(m, u_int8_t *);
@@ -443,19 +509,12 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
*(u_int16_t *)frm = htole16(arg); /* status */
frm += 2;
- if (arg == IEEE80211_STATUS_SUCCESS && ni != NULL)
+ if (arg == IEEE80211_STATUS_SUCCESS)
*(u_int16_t *)frm = htole16(ni->ni_associd);
- else
- *(u_int16_t *)frm = htole16(0);
frm += 2;
- if (ni != NULL) {
- frm = ieee80211_add_rates(frm, &ni->ni_rates);
- frm = ieee80211_add_xrates(frm, &ni->ni_rates);
- } else {
- frm = ieee80211_add_rates(frm, &ic->ic_bss->ni_rates);
- frm = ieee80211_add_xrates(frm, &ic->ic_bss->ni_rates);
- }
+ frm = ieee80211_add_rates(frm, &ni->ni_rates);
+ frm = ieee80211_add_xrates(frm, &ni->ni_rates);
m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
break;
@@ -465,7 +524,7 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
ether_sprintf(ni->ni_macaddr), arg);
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL)
- return ENOMEM;
+ senderr(ENOMEM);
MH_ALIGN(m, 2);
m->m_pkthdr.len = m->m_len = 2;
*mtod(m, u_int16_t *) = htole16(arg); /* reason */
@@ -474,11 +533,19 @@ ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
default:
IEEE80211_DPRINTF(("%s: invalid mgmt frame type %u\n",
__func__, type));
- return EINVAL;
+ senderr(EINVAL);
+ /* NOTREACHED */
}
ret = ieee80211_mgmt_output(ifp, ni, m, type);
- if (ret == 0 && timer)
- ic->ic_mgt_timer = timer;
+ if (ret == 0) {
+ if (timer)
+ ic->ic_mgt_timer = timer;
+ } else {
+bad:
+ if (ni != ic->ic_bss) /* remove ref we added */
+ ieee80211_free_node(ic, ni);
+ }
return ret;
+#undef senderr
}
diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h
index 81627ff..8c85003 100644
--- a/sys/net80211/ieee80211_proto.h
+++ b/sys/net80211/ieee80211_proto.h
@@ -55,15 +55,15 @@ extern const char *ieee80211_mgt_subtype_name[];
extern void ieee80211_proto_attach(struct ifnet *);
extern void ieee80211_proto_detach(struct ifnet *);
+struct ieee80211_node;
extern void ieee80211_input(struct ifnet *, struct mbuf *,
- int, u_int32_t, u_int);
-extern void ieee80211_recv_mgmt(struct ieee80211com *, struct mbuf *, int,
- int, u_int32_t, u_int);
+ struct ieee80211_node *, int, u_int32_t);
+extern void ieee80211_recv_mgmt(struct ieee80211com *, struct mbuf *,
+ struct ieee80211_node *, int, int, u_int32_t);
extern int ieee80211_send_mgmt(struct ieee80211com *, struct ieee80211_node *,
int, int);
-extern int ieee80211_mgmt_output(struct ifnet *, struct ieee80211_node *,
- struct mbuf *, int);
-extern struct mbuf *ieee80211_encap(struct ifnet *, struct mbuf *);
+extern struct mbuf *ieee80211_encap(struct ifnet *, struct mbuf *,
+ struct ieee80211_node **);
extern struct mbuf *ieee80211_decap(struct ifnet *, struct mbuf *);
extern u_int8_t *ieee80211_add_rates(u_int8_t *frm,
const struct ieee80211_rateset *);
diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h
index af47773..187ab79 100644
--- a/sys/net80211/ieee80211_var.h
+++ b/sys/net80211/ieee80211_var.h
@@ -135,7 +135,8 @@ struct ieee80211_channel {
struct ieee80211com {
struct arpcom ic_ac;
void (*ic_recv_mgmt)(struct ieee80211com *,
- struct mbuf *, int, int, u_int32_t, u_int);
+ struct mbuf *, struct ieee80211_node *,
+ int, int, u_int32_t);
int (*ic_send_mgmt)(struct ieee80211com *,
struct ieee80211_node *, int, int);
int (*ic_newstate)(struct ieee80211com *,
OpenPOWER on IntegriCloud