diff options
author | sam <sam@FreeBSD.org> | 2006-08-05 04:58:25 +0000 |
---|---|---|
committer | sam <sam@FreeBSD.org> | 2006-08-05 04:58:25 +0000 |
commit | 850b9c89c40046982f5e1947289cee5e825f307c (patch) | |
tree | 8181f9746f4413eebd9724c7f5b94e97cd6219a6 | |
parent | b780aa911eb8bb1f888360675b0239c4d2f3cb00 (diff) | |
download | FreeBSD-src-850b9c89c40046982f5e1947289cee5e825f307c.zip FreeBSD-src-850b9c89c40046982f5e1947289cee5e825f307c.tar.gz |
raw 802.11 packet transmit support
Submitted by: Andrea Bittau <a.bittau@cs.ucl.ac.uk>
-rw-r--r-- | sys/dev/wi/if_wavelan_ieee.h | 3 | ||||
-rw-r--r-- | sys/dev/wi/if_wi.c | 175 | ||||
-rw-r--r-- | sys/dev/wi/if_wireg.h | 1 |
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 /* |