raw 802.11 packet transmit support

Submitted by:	Andrea Bittau <a.bittau@cs.ucl.ac.uk>
This commit is contained in:
sam 2006-08-05 04:58:25 +00:00
parent b780aa911e
commit 850b9c89c4
3 changed files with 149 additions and 32 deletions

View File

@ -226,6 +226,7 @@ struct wi_counters {
#define WI_RID_P2_CRYPT_KEY2 0xFC26
#define WI_RID_P2_CRYPT_KEY3 0xFC27
#define WI_RID_P2_ENCRYPTION 0xFC28
#define WI_RID_ALT_RETRY_CNT 0xFC32
#define PRIVACY_INVOKED 0x01
#define EXCLUDE_UNENCRYPTED 0x02
#define HOST_ENCRYPT 0x10
@ -466,7 +467,7 @@ struct wi_rx_frame {
u_int8_t wi_src_addr[6];
u_int16_t wi_len;
};
#define WI_DATA_HDRLEN 0x44
#define WI_DATA_HDRLEN 0x3C
#define WI_MGMT_HDRLEN 0x3C
#define WI_CTL_HDRLEN 0x3C

View File

@ -114,6 +114,10 @@ __FBSDID("$FreeBSD$");
#include <dev/wi/if_wivar.h>
static void wi_start(struct ifnet *);
static int wi_start_tx(struct ifnet *ifp, struct wi_frame *frmhdr,
struct mbuf *m0);
static int wi_raw_xmit(struct ieee80211_node *, struct mbuf *,
const struct ieee80211_bpf_params *);
static int wi_reset(struct wi_softc *);
static void wi_watchdog(struct ifnet *);
static int wi_ioctl(struct ifnet *, u_long, caddr_t);
@ -490,6 +494,7 @@ wi_attach(device_t dev)
sc->sc_key_alloc = ic->ic_crypto.cs_key_alloc;
ic->ic_crypto.cs_key_alloc = wi_key_alloc;
ic->ic_newstate = wi_newstate;
ic->ic_raw_xmit = wi_raw_xmit;
ieee80211_media_init(ic, wi_media_change, wi_media_status);
#if NBPFILTER > 0
@ -695,8 +700,16 @@ wi_init(void *arg)
wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_HOSTAP);
break;
case IEEE80211_M_MONITOR:
if (sc->sc_firmware_type == WI_LUCENT)
switch (sc->sc_firmware_type) {
case WI_LUCENT:
wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_ADHOC);
break;
case WI_INTERSIL:
wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_APSILENT);
break;
}
wi_cmd(sc, WI_CMD_DEBUG | (WI_TEST_MONITOR << 8), 0, 0, 0);
break;
}
@ -736,6 +749,7 @@ wi_init(void *arg)
wi_write_val(sc, WI_RID_MICROWAVE_OVEN, sc->sc_microwave_oven);
wi_write_txrate(sc);
wi_write_ssid(sc, WI_RID_NODENAME, sc->sc_nodename, sc->sc_nodelen);
wi_write_val(sc, WI_RID_ALT_RETRY_CNT, 0); /* for IEEE80211_BPF_NOACK */
if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
sc->sc_firmware_type == WI_INTERSIL) {
@ -883,7 +897,7 @@ wi_start(struct ifnet *ifp)
struct ether_header *eh;
struct mbuf *m0;
struct wi_frame frmhdr;
int cur, fid, off, error;
int cur;
WI_LOCK_DECL();
WI_LOCK(sc);
@ -993,33 +1007,135 @@ wi_start(struct ifnet *ifp)
frmhdr.wi_dat_len = htole16(m0->m_pkthdr.len);
if (IFF_DUMPPKTS(ifp))
wi_dump_pkt(&frmhdr, NULL, -1);
fid = sc->sc_txd[cur].d_fid;
off = sizeof(frmhdr);
error = wi_write_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0
|| wi_mwrite_bap(sc, fid, off, m0, m0->m_pkthdr.len) != 0;
m_freem(m0);
if (ni != NULL)
ieee80211_free_node(ni);
if (error) {
ifp->if_oerrors++;
if (wi_start_tx(ifp, &frmhdr, m0))
continue;
}
sc->sc_txd[cur].d_len = off;
if (sc->sc_txcur == cur) {
if (wi_cmd(sc, WI_CMD_TX | WI_RECLAIM, fid, 0, 0)) {
if_printf(ifp, "xmit failed\n");
sc->sc_txd[cur].d_len = 0;
continue;
}
sc->sc_tx_timer = 5;
ifp->if_timer = 1;
}
sc->sc_txnext = cur = (cur + 1) % sc->sc_ntxbuf;
}
WI_UNLOCK(sc);
}
static int
wi_start_tx(struct ifnet *ifp, struct wi_frame *frmhdr, struct mbuf *m0)
{
struct wi_softc *sc = ifp->if_softc;
int cur = sc->sc_txnext;
int fid, off, error;
fid = sc->sc_txd[cur].d_fid;
off = sizeof(*frmhdr);
error = wi_write_bap(sc, fid, 0, frmhdr, sizeof(*frmhdr)) != 0
|| wi_mwrite_bap(sc, fid, off, m0, m0->m_pkthdr.len) != 0;
m_freem(m0);
if (error) {
ifp->if_oerrors++;
return -1;
}
sc->sc_txd[cur].d_len = off;
if (sc->sc_txcur == cur) {
if (wi_cmd(sc, WI_CMD_TX | WI_RECLAIM, fid, 0, 0)) {
if_printf(ifp, "xmit failed\n");
sc->sc_txd[cur].d_len = 0;
return -1;
}
sc->sc_tx_timer = 5;
ifp->if_timer = 1;
}
return 0;
}
static int
wi_raw_xmit(struct ieee80211_node *ni, struct mbuf *m0,
const struct ieee80211_bpf_params *params)
{
struct ieee80211com *ic = ni->ni_ic;
struct ifnet *ifp = ic->ic_ifp;
struct wi_softc *sc = ifp->if_softc;
struct ieee80211_frame *wh;
struct wi_frame frmhdr;
int cur;
int rc = 0;
WI_LOCK_DECL();
WI_LOCK(sc);
if (sc->wi_gone) {
rc = ENETDOWN;
goto out;
}
if (sc->sc_flags & WI_FLAGS_OUTRANGE) {
rc = ENETDOWN;
goto out;
}
memset(&frmhdr, 0, sizeof(frmhdr));
cur = sc->sc_txnext;
if (sc->sc_txd[cur].d_len != 0) {
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
rc = ENOBUFS;
goto out;
}
m0->m_pkthdr.rcvif = NULL;
m_copydata(m0, 4, ETHER_ADDR_LEN * 2,
(caddr_t)&frmhdr.wi_ehdr);
frmhdr.wi_ehdr.ether_type = 0;
wh = mtod(m0, struct ieee80211_frame *);
#if NBPFILTER > 0
if (bpf_peers_present(ic->ic_rawbpf))
bpf_mtap(ic->ic_rawbpf, m0);
#endif
frmhdr.wi_tx_ctl = htole16(WI_ENC_TX_802_11|WI_TXCNTL_TX_EX);
if (params && (params->ibp_flags & IEEE80211_BPF_NOACK))
frmhdr.wi_tx_ctl |= htole16(WI_TXCNTL_ALTRTRY);
/* XXX check key for SWCRYPT instead of using operating mode */
if ((wh->i_fc[1] & IEEE80211_FC1_WEP) &&
(sc->sc_encryption & HOST_ENCRYPT)) {
if (!params ||
(params && (params->ibp_flags & IEEE80211_BPF_CRYPTO))) {
struct ieee80211_key *k;
k = ieee80211_crypto_encap(ic, ni, m0);
if (k == NULL) {
if (ni != NULL)
ieee80211_free_node(ni);
m_freem(m0);
rc = ENOMEM;
goto out;
}
frmhdr.wi_tx_ctl |= htole16(WI_TXCNTL_NOCRYPT);
}
}
#if NBPFILTER > 0
if (bpf_peers_present(sc->sc_drvbpf)) {
sc->sc_tx_th.wt_rate =
ni->ni_rates.rs_rates[ni->ni_txrate];
bpf_mtap2(sc->sc_drvbpf,
&sc->sc_tx_th, sc->sc_tx_th_len, m0);
}
#endif
m_copydata(m0, 0, sizeof(struct ieee80211_frame),
(caddr_t)&frmhdr.wi_whdr);
m_adj(m0, sizeof(struct ieee80211_frame));
frmhdr.wi_dat_len = htole16(m0->m_pkthdr.len);
if (IFF_DUMPPKTS(ifp))
wi_dump_pkt(&frmhdr, NULL, -1);
if (ni != NULL)
ieee80211_free_node(ni);
rc = wi_start_tx(ifp, &frmhdr, m0);
if (rc)
goto out;
sc->sc_txnext = cur = (cur + 1) % sc->sc_ntxbuf;
out:
WI_UNLOCK(sc);
return rc;
}
static int
wi_reset(struct wi_softc *sc)
{
@ -1522,17 +1638,6 @@ wi_rx_intr(struct wi_softc *sc)
CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_RX);
wh = mtod(m, struct ieee80211_frame *);
if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
/*
* WEP is decrypted by hardware and the IV
* is stripped. Clear WEP bit so we don't
* try to process it in ieee80211_input.
* XXX fix for TKIP, et. al.
*/
wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
}
#if NBPFILTER > 0
if (bpf_peers_present(sc->sc_drvbpf)) {
/* XXX replace divide by table */
@ -1547,6 +1652,16 @@ wi_rx_intr(struct wi_softc *sc)
&sc->sc_rx_th, sc->sc_rx_th_len, m);
}
#endif
wh = mtod(m, struct ieee80211_frame *);
if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
/*
* WEP is decrypted by hardware and the IV
* is stripped. Clear WEP bit so we don't
* try to process it in ieee80211_input.
* XXX fix for TKIP, et. al.
*/
wh->i_fc[1] &= ~IEEE80211_FC1_WEP;
}
/* synchronize driver's BSSID with firmware's BSSID */
dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;

View File

@ -496,6 +496,7 @@ struct wi_pcf {
#define WI_PORTTYPE_BSS 0x1
#define WI_PORTTYPE_WDS 0x2
#define WI_PORTTYPE_ADHOC 0x3
#define WI_PORTTYPE_APSILENT 0x5
#define WI_PORTTYPE_HOSTAP 0x6
/*