diff options
-rw-r--r-- | sys/dev/ath/if_ath.c | 107 | ||||
-rw-r--r-- | sys/dev/ath/if_athvar.h | 4 | ||||
-rw-r--r-- | sys/dev/wi/if_wi.c | 73 | ||||
-rw-r--r-- | sys/net80211/ieee80211_input.c | 128 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.c | 33 | ||||
-rw-r--r-- | sys/net80211/ieee80211_node.h | 3 | ||||
-rw-r--r-- | sys/net80211/ieee80211_output.c | 141 | ||||
-rw-r--r-- | sys/net80211/ieee80211_proto.h | 12 | ||||
-rw-r--r-- | sys/net80211/ieee80211_var.h | 3 |
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 *, |