summaryrefslogtreecommitdiffstats
path: root/sys/dev/wi
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2006-08-05 04:58:25 +0000
committersam <sam@FreeBSD.org>2006-08-05 04:58:25 +0000
commit850b9c89c40046982f5e1947289cee5e825f307c (patch)
tree8181f9746f4413eebd9724c7f5b94e97cd6219a6 /sys/dev/wi
parentb780aa911eb8bb1f888360675b0239c4d2f3cb00 (diff)
downloadFreeBSD-src-850b9c89c40046982f5e1947289cee5e825f307c.zip
FreeBSD-src-850b9c89c40046982f5e1947289cee5e825f307c.tar.gz
raw 802.11 packet transmit support
Submitted by: Andrea Bittau <a.bittau@cs.ucl.ac.uk>
Diffstat (limited to 'sys/dev/wi')
-rw-r--r--sys/dev/wi/if_wavelan_ieee.h3
-rw-r--r--sys/dev/wi/if_wi.c175
-rw-r--r--sys/dev/wi/if_wireg.h1
3 files changed, 148 insertions, 31 deletions
diff --git a/sys/dev/wi/if_wavelan_ieee.h b/sys/dev/wi/if_wavelan_ieee.h
index 585edaa..c726ec9 100644
--- a/sys/dev/wi/if_wavelan_ieee.h
+++ b/sys/dev/wi/if_wavelan_ieee.h
@@ -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
diff --git a/sys/dev/wi/if_wi.c b/sys/dev/wi/if_wi.c
index d1a5993..5a52a5f 100644
--- a/sys/dev/wi/if_wi.c
+++ b/sys/dev/wi/if_wi.c
@@ -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,31 +1007,133 @@ 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_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_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;
+ }
+ 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;
}
- sc->sc_tx_timer = 5;
- ifp->if_timer = 1;
+ frmhdr.wi_tx_ctl |= htole16(WI_TXCNTL_NOCRYPT);
}
- sc->sc_txnext = cur = (cur + 1) % sc->sc_ntxbuf;
}
-
+#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
@@ -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;
diff --git a/sys/dev/wi/if_wireg.h b/sys/dev/wi/if_wireg.h
index 7992f89..33cf5c9 100644
--- a/sys/dev/wi/if_wireg.h
+++ b/sys/dev/wi/if_wireg.h
@@ -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
/*
OpenPOWER on IntegriCloud