diff options
author | sam <sam@FreeBSD.org> | 2006-07-26 03:30:50 +0000 |
---|---|---|
committer | sam <sam@FreeBSD.org> | 2006-07-26 03:30:50 +0000 |
commit | 9a8b92caeb29a154c10e66285394ac111c5e5407 (patch) | |
tree | 2d7e3b4dd4423a966dc02679ad2ed77dcd0f182d /sys/dev/ral/rt2560.c | |
parent | a245550432954c7f1d3eebf64cf691435cc5f2f2 (diff) | |
download | FreeBSD-src-9a8b92caeb29a154c10e66285394ac111c5e5407.zip FreeBSD-src-9a8b92caeb29a154c10e66285394ac111c5e5407.tar.gz |
support for 802.11 packet injection via bpf
Reviewed by: arch@
MFC after: 1 month
Diffstat (limited to 'sys/dev/ral/rt2560.c')
-rw-r--r-- | sys/dev/ral/rt2560.c | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/sys/dev/ral/rt2560.c b/sys/dev/ral/rt2560.c index 652a089..f4266ff 100644 --- a/sys/dev/ral/rt2560.c +++ b/sys/dev/ral/rt2560.c @@ -146,6 +146,8 @@ static void rt2560_set_txantenna(struct rt2560_softc *, int); static void rt2560_set_rxantenna(struct rt2560_softc *, int); static void rt2560_init(void *); static void rt2560_stop(void *); +static int rt2560_raw_xmit(struct ieee80211_node *, struct mbuf *, + const struct ieee80211_bpf_params *); /* * Supported rates for 802.11a/b/g modes (in 500Kbps unit). @@ -327,6 +329,7 @@ rt2560_attach(device_t dev, int id) /* override state transition machine */ sc->sc_newstate = ic->ic_newstate; ic->ic_newstate = rt2560_newstate; + ic->ic_raw_xmit = rt2560_raw_xmit; ieee80211_media_init(ic, rt2560_media_change, ieee80211_media_status); bpfattach2(ifp, DLT_IEEE802_11_RADIO, @@ -1713,6 +1716,73 @@ rt2560_tx_mgt(struct rt2560_softc *sc, struct mbuf *m0, return 0; } +static int +rt2560_tx_raw(struct rt2560_softc *sc, struct mbuf *m0, + struct ieee80211_node *ni, const struct ieee80211_bpf_params *params) +{ + struct ieee80211com *ic = &sc->sc_ic; + struct rt2560_tx_desc *desc; + struct rt2560_tx_data *data; + bus_dma_segment_t segs[RT2560_MAX_SCATTER]; + uint32_t flags; + int nsegs, rate, error; + + desc = &sc->prioq.desc[sc->prioq.cur]; + data = &sc->prioq.data[sc->prioq.cur]; + + rate = params->ibp_rate0 & IEEE80211_RATE_VAL; + /* XXX validate */ + if (rate == 0) + return EINVAL; + + error = bus_dmamap_load_mbuf_sg(sc->prioq.data_dmat, data->map, m0, + segs, &nsegs, 0); + if (error != 0) { + device_printf(sc->sc_dev, "could not map mbuf (error %d)\n", + error); + m_freem(m0); + return error; + } + + if (bpf_peers_present(sc->sc_drvbpf)) { + struct rt2560_tx_radiotap_header *tap = &sc->sc_txtap; + + tap->wt_flags = 0; + tap->wt_rate = rate; + tap->wt_chan_freq = htole16(ic->ic_curchan->ic_freq); + tap->wt_chan_flags = htole16(ic->ic_curchan->ic_flags); + tap->wt_antenna = sc->tx_ant; + + bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0); + } + + data->m = m0; + data->ni = ni; + + flags = 0; + if ((params->ibp_flags & IEEE80211_BPF_NOACK) == 0) + flags |= RT2560_TX_ACK; + + /* XXX need to setup descriptor ourself */ + rt2560_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, + rate, (params->ibp_flags & IEEE80211_BPF_CRYPTO) != 0, + segs->ds_addr); + + bus_dmamap_sync(sc->prioq.data_dmat, data->map, BUS_DMASYNC_PREWRITE); + bus_dmamap_sync(sc->prioq.desc_dmat, sc->prioq.desc_map, + BUS_DMASYNC_PREWRITE); + + DPRINTFN(10, ("sending raw frame len=%u idx=%u rate=%u\n", + m0->m_pkthdr.len, sc->prioq.cur, rate)); + + /* kick prio */ + sc->prioq.queued++; + sc->prioq.cur = (sc->prioq.cur + 1) % RT2560_PRIO_RING_COUNT; + RAL_WRITE(sc, RT2560_TXCSR0, RT2560_KICK_PRIO); + + return 0; +} + /* * Build a RTS control frame. */ @@ -2722,3 +2792,58 @@ rt2560_stop(void *priv) rt2560_reset_tx_ring(sc, &sc->bcnq); rt2560_reset_rx_ring(sc, &sc->rxq); } + +static int +rt2560_raw_xmit(struct ieee80211_node *ni, struct mbuf *m, + const struct ieee80211_bpf_params *params) +{ + struct ieee80211com *ic = ni->ni_ic; + struct ifnet *ifp = ic->ic_ifp; + struct rt2560_softc *sc = ifp->if_softc; + + RAL_LOCK(sc); + + /* prevent management frames from being sent if we're not ready */ + if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { + RAL_UNLOCK(sc); + return ENETDOWN; + } + if (sc->prioq.queued >= RT2560_PRIO_RING_COUNT) { + ifp->if_drv_flags |= IFF_DRV_OACTIVE; + RAL_UNLOCK(sc); + return ENOBUFS; /* XXX */ + } + + if (bpf_peers_present(ic->ic_rawbpf)) + bpf_mtap(ic->ic_rawbpf, m); + + ifp->if_opackets++; + + if (params == NULL) { + /* + * Legacy path; interpret frame contents to decide + * precisely how to send the frame. + */ + if (rt2560_tx_mgt(sc, m, ni) != 0) + goto bad; + } else { + /* + * Caller supplied explicit parameters to use in + * sending the frame. + */ + if (rt2560_tx_raw(sc, m, ni, params)) + goto bad; + } + sc->sc_tx_timer = 5; + ifp->if_timer = 1; + + RAL_UNLOCK(sc); + + return 0; +bad: + ifp->if_oerrors++; + if (ni != NULL) + ieee80211_free_node(ni); + RAL_UNLOCK(sc); + return EIO; /* XXX */ +} |