support for 802.11 packet injection via bpf
Reviewed by: arch@ MFC after: 1 month
This commit is contained in:
parent
246b546762
commit
9ee0e22742
@ -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 */
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user