summaryrefslogtreecommitdiffstats
path: root/sys/dev/ral/rt2560.c
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2006-07-26 03:30:50 +0000
committersam <sam@FreeBSD.org>2006-07-26 03:30:50 +0000
commit9a8b92caeb29a154c10e66285394ac111c5e5407 (patch)
tree2d7e3b4dd4423a966dc02679ad2ed77dcd0f182d /sys/dev/ral/rt2560.c
parenta245550432954c7f1d3eebf64cf691435cc5f2f2 (diff)
downloadFreeBSD-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.c125
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 */
+}
OpenPOWER on IntegriCloud