support for 802.11 packet injection via bpf

Reviewed by:	arch@
MFC after:	1 month
This commit is contained in:
Sam Leffler 2006-07-26 03:30:50 +00:00
parent 246b546762
commit 9ee0e22742
2 changed files with 243 additions and 0 deletions

View File

@ -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 */
}

View File

@ -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,
@ -1245,6 +1248,74 @@ ural_tx_mgt(struct ural_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
return 0;
}
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)
{
@ -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