summaryrefslogtreecommitdiffstats
path: root/sys/dev
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
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')
-rw-r--r--sys/dev/ral/rt2560.c125
-rw-r--r--sys/dev/usb/if_ural.c118
2 files changed, 243 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 */
+}
diff --git a/sys/dev/usb/if_ural.c b/sys/dev/usb/if_ural.c
index 40b8dd3..fbf4c52 100644
--- a/sys/dev/usb/if_ural.c
+++ b/sys/dev/usb/if_ural.c
@@ -163,6 +163,8 @@ Static void ural_set_txantenna(struct ural_softc *, int);
Static void ural_set_rxantenna(struct ural_softc *, int);
Static void ural_init(void *);
Static void ural_stop(void *);
+static int ural_raw_xmit(struct ieee80211_node *, struct mbuf *,
+ const struct ieee80211_bpf_params *);
Static void ural_amrr_start(struct ural_softc *,
struct ieee80211_node *);
Static void ural_amrr_timeout(void *);
@@ -507,6 +509,7 @@ USB_ATTACH(ural)
/* override state transition machine */
sc->sc_newstate = ic->ic_newstate;
ic->ic_newstate = ural_newstate;
+ ic->ic_raw_xmit = ural_raw_xmit;
ieee80211_media_init(ic, ural_media_change, ieee80211_media_status);
bpfattach2(ifp, DLT_IEEE802_11_RADIO,
@@ -1246,6 +1249,74 @@ ural_tx_mgt(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
}
Static int
+ural_tx_raw(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni,
+ const struct ieee80211_bpf_params *params)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ural_tx_desc *desc;
+ struct ural_tx_data *data;
+ uint32_t flags;
+ usbd_status error;
+ int xferlen, rate;
+
+ data = &sc->tx_data[0];
+ desc = (struct ural_tx_desc *)data->buf;
+
+ rate = params->ibp_rate0 & IEEE80211_RATE_VAL;
+ /* XXX validate */
+ if (rate == 0)
+ return EINVAL;
+
+ if (bpf_peers_present(sc->sc_drvbpf)) {
+ struct ural_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 |= RAL_TX_ACK;
+
+ m_copydata(m0, 0, m0->m_pkthdr.len, data->buf + RAL_TX_DESC_SIZE);
+ /* XXX need to setup descriptor ourself */
+ ural_setup_tx_desc(sc, desc, flags, m0->m_pkthdr.len, rate);
+
+ /* align end on a 2-bytes boundary */
+ xferlen = (RAL_TX_DESC_SIZE + m0->m_pkthdr.len + 1) & ~1;
+
+ /*
+ * No space left in the last URB to store the extra 2 bytes, force
+ * sending of another URB.
+ */
+ if ((xferlen % 64) == 0)
+ xferlen += 2;
+
+ DPRINTFN(10, ("sending raw frame len=%u rate=%u xfer len=%u\n",
+ m0->m_pkthdr.len, rate, xferlen));
+
+ usbd_setup_xfer(data->xfer, sc->sc_tx_pipeh, data, data->buf,
+ xferlen, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, RAL_TX_TIMEOUT,
+ ural_txeof);
+
+ error = usbd_transfer(data->xfer);
+ if (error != USBD_NORMAL_COMPLETION && error != USBD_IN_PROGRESS)
+ return error;
+
+ sc->tx_queued++;
+
+ return 0;
+}
+
+Static int
ural_tx_data(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
{
struct ieee80211com *ic = &sc->sc_ic;
@@ -2248,6 +2319,53 @@ ural_stop(void *priv)
ural_free_tx_list(sc);
}
+static int
+ural_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 ural_softc *sc = ifp->if_softc;
+
+ /* prevent management frames from being sent if we're not ready */
+ if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
+ return ENETDOWN;
+ if (sc->tx_queued >= RAL_TX_LIST_COUNT) {
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ return EIO;
+ }
+
+ 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 (ural_tx_mgt(sc, m, ni) != 0)
+ goto bad;
+ } else {
+ /*
+ * Caller supplied explicit parameters to use in
+ * sending the frame.
+ */
+ if (ural_tx_raw(sc, m, ni, params) != 0)
+ goto bad;
+ }
+ sc->sc_tx_timer = 5;
+ ifp->if_timer = 1;
+
+ return 0;
+bad:
+ ifp->if_oerrors++;
+ if (ni != NULL)
+ ieee80211_free_node(ni);
+ return EIO; /* XXX */
+}
+
#define URAL_AMRR_MIN_SUCCESS_THRESHOLD 1
#define URAL_AMRR_MAX_SUCCESS_THRESHOLD 10
OpenPOWER on IntegriCloud