diff --git a/sys/dev/wi/if_wi.c b/sys/dev/wi/if_wi.c index 2fd33d573df1..e8182d0f758f 100644 --- a/sys/dev/wi/if_wi.c +++ b/sys/dev/wi/if_wi.c @@ -100,6 +100,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include @@ -110,8 +111,8 @@ __FBSDID("$FreeBSD$"); #include #include -#include #include +#include #define IF_POLL(ifq, m) ((m) = (ifq)->ifq_head) #define IFQ_POLL(ifq, m) IF_POLL((ifq), (m)) @@ -372,6 +373,10 @@ wi_attach(device_t dev) ic->ic_caps |= IEEE80211_C_MONITOR; } sc->sc_ibss_port = htole16(1); + + sc->sc_min_rssi = WI_LUCENT_MIN_RSSI; + sc->sc_max_rssi = WI_LUCENT_MAX_RSSI; + sc->sc_dbm_offset = WI_LUCENT_DBM_OFFSET; break; case WI_INTERSIL: @@ -393,6 +398,10 @@ wi_attach(device_t dev) if (sc->sc_sta_firmware_ver >= 803) ic->ic_caps |= IEEE80211_C_HOSTAP; sc->sc_ibss_port = htole16(0); + + sc->sc_min_rssi = WI_PRISM_MIN_RSSI; + sc->sc_max_rssi = WI_PRISM_MAX_RSSI; + sc->sc_dbm_offset = WI_PRISM_DBM_OFFSET; break; case WI_SYMBOL: @@ -401,6 +410,10 @@ wi_attach(device_t dev) if (sc->sc_sta_firmware_ver >= 25000) ic->ic_caps |= IEEE80211_C_IBSS; sc->sc_ibss_port = htole16(4); + + sc->sc_min_rssi = WI_PRISM_MIN_RSSI; + sc->sc_max_rssi = WI_PRISM_MAX_RSSI; + sc->sc_dbm_offset = WI_PRISM_DBM_OFFSET; break; } @@ -431,9 +444,8 @@ wi_attach(device_t dev) buflen = sizeof(val); if ((sc->sc_flags & WI_FLAGS_HAS_DBMADJUST) && wi_read_rid(sc, WI_RID_DBM_ADJUST, &val, &buflen) == 0) { - sc->sc_dbm_adjust = le16toh(val); - } else - sc->sc_dbm_adjust = 100; /* default */ + sc->sc_dbm_offset = le16toh(val); + } sc->sc_max_datalen = 2304; sc->sc_system_scale = 1; @@ -460,6 +472,23 @@ wi_attach(device_t dev) ic->ic_newstate = wi_newstate; ieee80211_media_init(ifp, wi_media_change, wi_media_status); +#if NBPFILTER > 0 + bpfattach2(ifp, DLT_IEEE802_11_RADIO, + sizeof(struct ieee80211_frame) + sizeof(sc->sc_tx_th), + &sc->sc_drvbpf); + /* + * Initialize constant fields. + * + * NB: the channel is setup each time we transition to the + * RUN state to avoid filling it in for each frame. + */ + sc->sc_tx_th.wt_ihdr.it_len = sizeof(sc->sc_tx_th); + sc->sc_tx_th.wt_ihdr.it_present = WI_TX_RADIOTAP_PRESENT; + + sc->sc_rx_th.wr_ihdr.it_len = sizeof(sc->sc_rx_th); + sc->sc_rx_th.wr_ihdr.it_present = WI_RX_RADIOTAP_PRESENT0; + sc->sc_rx_th.wr_present1 = WI_RX_RADIOTAP_PRESENT1; +#endif return (0); } @@ -477,6 +506,9 @@ wi_detach(device_t dev) wi_stop(ifp, 0); +#if NBPFILTER > 0 + bpfdetach(ifp); +#endif ieee80211_ifdetach(ifp); WI_UNLOCK(sc); bus_teardown_intr(dev, sc->irq, sc->wi_intrhand); @@ -902,10 +934,9 @@ wi_start(struct ifnet *ifp) MGETHDR(mb, M_DONTWAIT, m0->m_type); if (mb != NULL) { - (void) m_dup_pkthdr(mb, m0, M_DONTWAIT); mb->m_next = m0; - mb->m_data = (caddr_t)&frmhdr; - mb->m_len = sizeof(frmhdr); + mb->m_data = (caddr_t)&sc->sc_tx_th; + mb->m_len = sizeof(sc->sc_tx_th); mb->m_pkthdr.len += mb->m_len; bpf_mtap(sc->sc_drvbpf, mb); m_free(mb); @@ -1449,12 +1480,23 @@ wi_rx_intr(struct wi_softc *sc) if (sc->sc_drvbpf) { struct mbuf *mb; + /* XXX pre-allocate space when setting up recv's */ MGETHDR(mb, M_DONTWAIT, m->m_type); if (mb != NULL) { + /* XXX replace divide by table */ + sc->sc_rx_th.wr_rate = frmhdr.wi_rx_rate / 5; + sc->sc_rx_th.wr_antsignal = + WI_RSSI_TO_DBM(sc, frmhdr.wi_rx_signal); + sc->sc_rx_th.wr_antnoise = + WI_RSSI_TO_DBM(sc, frmhdr.wi_rx_silence); + sc->sc_rx_th.wr_time = + htole32((frmhdr.wi_rx_tstamp1 << 16) | + frmhdr.wi_rx_tstamp0); + (void) m_dup_pkthdr(mb, m, M_DONTWAIT); mb->m_next = m; - mb->m_data = (caddr_t)&frmhdr; - mb->m_len = sizeof(frmhdr); + mb->m_data = (caddr_t)&sc->sc_rx_th; + mb->m_len = sizeof(sc->sc_rx_th); mb->m_pkthdr.len += mb->m_len; bpf_mtap(sc->sc_drvbpf, mb); m_free(mb); @@ -1837,7 +1879,7 @@ wi_get_cfg(struct ifnet *ifp, u_long cmd, caddr_t data) &len); break; } - wreq.wi_val[0] = htole16(sc->sc_dbm_adjust); + wreq.wi_val[0] = htole16(sc->sc_dbm_offset); len = sizeof(u_int16_t); break; @@ -2608,6 +2650,12 @@ wi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) wi_read_rid(sc, WI_RID_CURRENT_CHAN, &val, &buflen); /* XXX validate channel */ ni->ni_chan = &ic->ic_channels[le16toh(val)]; +#if NBPFILTER > 0 + sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq = + htole16(ni->ni_chan->ic_freq); + sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags = + htole16(ni->ni_chan->ic_flags); +#endif if (IEEE80211_ADDR_EQ(old_bssid, ni->ni_bssid)) sc->sc_false_syns++; diff --git a/sys/dev/wi/if_wi_pccard.c b/sys/dev/wi/if_wi_pccard.c index f5fb334437cc..23d3f2e2ac6a 100644 --- a/sys/dev/wi/if_wi_pccard.c +++ b/sys/dev/wi/if_wi_pccard.c @@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #if __FreeBSD_version >= 500000 @@ -69,8 +70,8 @@ __FBSDID("$FreeBSD$"); #endif #include -#include #include +#include #ifdef WI_SYMBOL_FIRMWARE #include #endif diff --git a/sys/dev/wi/if_wi_pci.c b/sys/dev/wi/if_wi_pci.c index 78dd0a2a314e..6639fc10aa9d 100644 --- a/sys/dev/wi/if_wi_pci.c +++ b/sys/dev/wi/if_wi_pci.c @@ -62,10 +62,11 @@ #include #include +#include #include -#include #include +#include static int wi_pci_probe(device_t); static int wi_pci_attach(device_t); diff --git a/sys/dev/wi/if_wireg.h b/sys/dev/wi/if_wireg.h index a4154058634d..5d17211391d6 100644 --- a/sys/dev/wi/if_wireg.h +++ b/sys/dev/wi/if_wireg.h @@ -679,3 +679,39 @@ struct wi_frame { */ #define WI_HFA386X_CR_A_D_TEST_MODES2 0x1A #define WI_HFA386X_CR_MANUAL_TX_POWER 0x3E + +#ifdef IEEE80211_RADIOTAP_F_CFP +/* + * Radio capture format for Prism. + */ +#define WI_RX_RADIOTAP_PRESENT0 \ + ((1 << IEEE80211_RADIOTAP_FLAGS) | \ + (1 << IEEE80211_RADIOTAP_RATE) | \ + (1 << IEEE80211_RADIOTAP_CHANNEL) | \ + (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) | \ + (1 << IEEE80211_RADIOTAP_DB_ANTNOISE) | \ + (1 << IEEE80211_RADIOTAP_EXT)) + +#define WI_RX_RADIOTAP_PRESENT1 (1 << (IEEE80211_RADIOTAP_TIME - 32)) + +struct wi_rx_radiotap_header { + struct ieee80211_radiotap_header wr_ihdr; + u_int32_t wr_present1; + u_int8_t wr_flags; + u_int8_t wr_rate; + u_int16_t wr_chan_freq; + u_int16_t wr_chan_flags; + u_int8_t wr_antsignal; + u_int8_t wr_antnoise; + u_int32_t wr_time; +}; + +#define WI_TX_RADIOTAP_PRESENT \ + ((1 << IEEE80211_RADIOTAP_CHANNEL)) + +struct wi_tx_radiotap_header { + struct ieee80211_radiotap_header wt_ihdr; + u_int16_t wt_chan_freq; + u_int16_t wt_chan_flags; +}; +#endif /* IEEE80211_RADIOTAP_F_CFP */ diff --git a/sys/dev/wi/if_wivar.h b/sys/dev/wi/if_wivar.h index 0ec3df394153..dbfc627114d0 100644 --- a/sys/dev/wi/if_wivar.h +++ b/sys/dev/wi/if_wivar.h @@ -106,7 +106,11 @@ struct wi_softc { u_int16_t sc_procframe; u_int16_t sc_portnum; - u_int16_t sc_dbm_adjust; + /* RSSI interpretation */ + u_int16_t sc_min_rssi; /* clamp sc_min_rssi < RSSI */ + u_int16_t sc_max_rssi; /* clamp RSSI < sc_max_rssi */ + u_int16_t sc_dbm_offset; /* dBm ~ RSSI - sc_dbm_offset */ + u_int16_t sc_max_datalen; u_int16_t sc_system_scale; u_int16_t sc_cnfauthmode; @@ -158,8 +162,19 @@ struct wi_softc { int sc_false_syns; u_int16_t sc_txbuf[IEEE80211_MAX_LEN/2]; + + union { + struct wi_tx_radiotap_header th; + u_int8_t pad[64]; + } u_tx_rt; + union { + struct wi_rx_radiotap_header th; + u_int8_t pad[64]; + } u_rx_rt; }; #define sc_if sc_ic.ic_if +#define sc_tx_th u_tx_rt.th +#define sc_rx_th u_rx_rt.th /* maximum consecutive false change-of-BSSID indications */ #define WI_MAX_FALSE_SYNS 10 @@ -184,6 +199,17 @@ struct wi_card_ident { u_int8_t firm_type; }; +#define WI_PRISM_MIN_RSSI 0x1b +#define WI_PRISM_MAX_RSSI 0x9a +#define WI_PRISM_DBM_OFFSET 100 /* XXX */ + +#define WI_LUCENT_MIN_RSSI 47 +#define WI_LUCENT_MAX_RSSI 138 +#define WI_LUCENT_DBM_OFFSET 149 + +#define WI_RSSI_TO_DBM(sc, rssi) (MIN((sc)->sc_max_rssi, \ + MAX((sc)->sc_min_rssi, (rssi))) - (sc)->sc_dbm_offset) + #if __FreeBSD_version < 500000 /* * Various compat hacks/kludges