PERFORCE change 138040 for review
Sam Leffler
sam at FreeBSD.org
Tue Mar 18 19:23:32 UTC 2008
http://perforce.freebsd.org/chv.cgi?CH=138040
Change 138040 by sam at sam_ebb on 2008/03/18 19:22:30
checkpoint; still not usable
Affected files ...
.. //depot/projects/vap/sys/dev/wi/if_wi.c#12 edit
.. //depot/projects/vap/sys/dev/wi/if_wi_pccard.c#6 edit
.. //depot/projects/vap/sys/dev/wi/if_wivar.h#9 edit
.. //depot/projects/vap/sys/dev/wi/spectrum24t_cf.h#3 delete
Differences ...
==== //depot/projects/vap/sys/dev/wi/if_wi.c#12 (text+ko) ====
@@ -1,5 +1,3 @@
-/* $NetBSD: wi.c,v 1.109 2003/01/09 08:52:19 dyoung Exp $ */
-
/*-
* Copyright (c) 1997, 1998, 1999
* Bill Paul <wpaul at ctr.columbia.edu>. All rights reserved.
@@ -64,7 +62,6 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/dev/wi/if_wi.c,v 1.214 2007/09/16 20:02:29 thompsa Exp $");
-#define WI_HERMES_AUTOINC_WAR /* Work around data write autoinc bug. */
#define WI_HERMES_STATS_WAR /* Work around stats counter bug. */
#define NBPFILTER 1
@@ -112,16 +109,22 @@
#include <dev/wi/if_wireg.h>
#include <dev/wi/if_wivar.h>
+static struct ieee80211vap *wi_vap_create(struct ieee80211com *ic,
+ const char name[IFNAMSIZ], int unit, int opmode, int flags,
+ const uint8_t bssid[IEEE80211_ADDR_LEN],
+ const uint8_t mac[IEEE80211_ADDR_LEN]);
+static void wi_vap_delete(struct ieee80211vap *vap);
static void wi_start_locked(struct ifnet *);
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 void wi_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
+ int subtype, int rssi, int noise, u_int32_t rstamp);
static int wi_reset(struct ifnet *);
static void wi_watchdog(void *);
static int wi_ioctl(struct ifnet *, u_long, caddr_t);
-static int wi_media_change(struct ifnet *);
static void wi_media_status(struct ifnet *, struct ifmediareq *);
static void wi_rx_intr(struct wi_softc *);
@@ -129,16 +132,13 @@
static void wi_tx_ex_intr(struct wi_softc *);
static void wi_info_intr(struct wi_softc *);
-static int wi_key_alloc(struct ieee80211com *, const struct ieee80211_key *,
+static int wi_key_alloc(struct ieee80211vap *, const struct ieee80211_key *,
ieee80211_keyix *, ieee80211_keyix *);
-#if 0
-static int wi_get_cfg(struct ifnet *, u_long, caddr_t);
-static int wi_set_cfg(struct ifnet *, u_long, caddr_t);
-#endif
-static int wi_write_txrate(struct wi_softc *);
-static int wi_write_wep(struct wi_softc *);
+static int wi_write_txrate(struct wi_softc *, struct ieee80211vap *);
+static int wi_write_wep(struct wi_softc *, struct ieee80211vap *);
static int wi_write_multi(struct wi_softc *);
+static void wi_update_mcast(struct ifnet *);
static int wi_alloc_fid(struct wi_softc *, int, int *);
static void wi_read_nicid(struct wi_softc *);
static int wi_write_ssid(struct wi_softc *, int, u_int8_t *, int);
@@ -151,32 +151,13 @@
static int wi_read_rid(struct wi_softc *, int, void *, int *);
static int wi_write_rid(struct wi_softc *, int, void *, int);
-static int wi_newstate(struct ieee80211com *, enum ieee80211_state, int);
-
-static int wi_scan_ap(struct wi_softc *, u_int16_t, u_int16_t);
-static void wi_scan_result(struct wi_softc *, int, int);
+static int wi_newstate(struct ieee80211vap *, enum ieee80211_state, int);
static void wi_dump_pkt(struct wi_frame *, struct ieee80211_node *, int rssi);
-#if 0
-static int wi_get_debug(struct wi_softc *, struct wi_req *);
-static int wi_set_debug(struct wi_softc *, struct wi_req *);
-#endif
-
-/* support to download firmware for symbol CF card */
-static int wi_symbol_write_firm(struct wi_softc *, const void *, int,
- const void *, int);
-static int wi_symbol_set_hcr(struct wi_softc *, int);
-
static void wi_scan_start(struct ieee80211com *);
-static void wi_scan_curchan(struct ieee80211com *, unsigned long);
-static void wi_scan_mindwell(struct ieee80211com *);
static void wi_scan_end(struct ieee80211com *);
static void wi_set_channel(struct ieee80211com *);
-static void wi_update_slot(struct ifnet *);
-static struct ieee80211_node *wi_node_alloc(struct ieee80211_node_table *);
-static int wi_ioctl_get(struct ifnet *ifp, u_long command, caddr_t data);
-static int wi_ioctl_set(struct ifnet *ifp, u_long command, caddr_t data);
static __inline int
wi_write_val(struct wi_softc *sc, int rid, u_int16_t val)
@@ -270,7 +251,7 @@
if (ifp == NULL) {
device_printf(dev, "can not if_alloc\n");
wi_free(dev);
- return (ENOSPC);
+ return ENOSPC;
}
ifp->if_softc = sc;
@@ -284,19 +265,41 @@
if (error) {
device_printf(dev, "bus_setup_intr() failed! (%d)\n", error);
wi_free(dev);
- return (error);
+ return error;
}
- mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
- MTX_DEF | MTX_RECURSE);
- callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0);
-
sc->sc_firmware_type = WI_NOTYPE;
sc->wi_cmd_count = 500;
/* Reset the NIC. */
- if (wi_reset(ifp) != 0)
+ if (wi_reset(ifp) != 0) {
+ wi_free(dev);
return ENXIO; /* XXX */
+ }
+ /* Read NIC identification */
+ wi_read_nicid(sc);
+ switch (sc->sc_firmware_type) {
+ case WI_LUCENT:
+ if (sc->sc_sta_firmware_ver < 60006)
+ goto reject;
+ break;
+ case WI_INTERSIL:
+ if (sc->sc_sta_firmware_ver < 800)
+ goto reject;
+ break;
+ default:
+ reject:
+ device_printf(dev, "Sorry, this card is not supported "
+ "(type %d, firmware ver %d)\n",
+ sc->sc_firmware_type, sc->sc_sta_firmware_ver);
+ wi_free(dev);
+ return EOPNOTSUPP;
+ }
+
+ mtx_init(&sc->sc_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
+ MTX_DEF | MTX_RECURSE);
+ callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0);
+
/*
* Read the station address.
* And do it twice. I've seen PRISM-based cards that return
@@ -320,9 +323,6 @@
return (error);
}
- /* Read NIC identification */
- wi_read_nicid(sc);
-
if_initname(ifp, device_get_name(dev), device_get_unit(dev));
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_ioctl = wi_ioctl;
@@ -334,10 +334,11 @@
ic->ic_ifp = ifp;
ic->ic_phytype = IEEE80211_T_DS;
+ ic->ic_opmode = IEEE80211_M_STA;
ic->ic_caps = IEEE80211_C_PMGT
+ | IEEE80211_C_MONITOR
| IEEE80211_C_WEP /* everyone supports WEP */
;
- ic->ic_max_aid = WI_MAX_AID;
/*
* Query the card for available channels and setup the
@@ -358,61 +359,29 @@
c->ic_freq = ieee80211_ieee2mhz(i, IEEE80211_CHAN_B);
c->ic_flags = IEEE80211_CHAN_B;
c->ic_ieee = i;
+ /* XXX txpowers? */
}
/*
- * Read the default channel from the NIC. This may vary
- * depending on the country where the NIC was purchased, so
- * we can't hard-code a default and expect it to work for
- * everyone.
- *
- * If no channel is specified, let the 802.11 code select.
- */
- buflen = sizeof(val);
- if (wi_read_rid(sc, WI_RID_OWN_CHNL, &val, &buflen) == 0) {
- val = le16toh(val);
- ic->ic_bsschan = ieee80211_find_channel(ic,
- ieee80211_ieee2mhz(val, IEEE80211_CHAN_B),
- IEEE80211_CHAN_B);
- if (ic->ic_bsschan == NULL)
- ic->ic_bsschan = &ic->ic_channels[0];
- } else {
- device_printf(dev,
- "WI_RID_OWN_CHNL failed, using first channel!\n");
- ic->ic_bsschan = &ic->ic_channels[0];
- }
-
- /*
* Set flags based on firmware version.
*/
switch (sc->sc_firmware_type) {
case WI_LUCENT:
sc->sc_ntxbuf = 1;
- sc->sc_flags |= WI_FLAGS_HAS_SYSSCALE;
-#ifdef WI_HERMES_AUTOINC_WAR
- /* XXX: not confirmed, but never seen for recent firmware */
- if (sc->sc_sta_firmware_ver < 40000) {
- sc->sc_flags |= WI_FLAGS_BUG_AUTOINC;
- }
-#endif
- if (sc->sc_sta_firmware_ver >= 60000)
- sc->sc_flags |= WI_FLAGS_HAS_MOR;
- if (sc->sc_sta_firmware_ver >= 60006) {
- ic->ic_caps |= IEEE80211_C_IBSS;
- ic->ic_caps |= IEEE80211_C_MONITOR;
- }
+ sc->sc_flags |= WI_FLAGS_HAS_SYSSCALE
+ | WI_FLAGS_HAS_MOR;
+ ic->ic_caps |= IEEE80211_C_IBSS;
+
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:
sc->sc_ntxbuf = WI_NTXBUF;
- sc->sc_flags |= WI_FLAGS_HAS_FRAGTHR;
- sc->sc_flags |= WI_FLAGS_HAS_ROAMING;
- sc->sc_flags |= WI_FLAGS_HAS_SYSSCALE;
+ sc->sc_flags |= WI_FLAGS_HAS_FRAGTHR
+ | WI_FLAGS_HAS_ROAMING
+ | WI_FLAGS_HAS_SYSSCALE;
/*
* Old firmware are slow, so give peace a chance.
*/
@@ -420,35 +389,20 @@
sc->wi_cmd_count = 5000;
if (sc->sc_sta_firmware_ver > 10101)
sc->sc_flags |= WI_FLAGS_HAS_DBMADJUST;
- if (sc->sc_sta_firmware_ver >= 800) {
- ic->ic_caps |= IEEE80211_C_IBSS;
- ic->ic_caps |= IEEE80211_C_MONITOR;
- }
+ ic->ic_caps |= IEEE80211_C_IBSS;
/*
* version 0.8.3 and newer are the only ones that are known
* to currently work. Earlier versions can be made to work,
- * at least according to the Linux driver.
+ * at least according to the Linux driver but we require
+ * monitor mode so this is irrelevant.
*/
- if (sc->sc_sta_firmware_ver >= 803)
- ic->ic_caps |= IEEE80211_C_HOSTAP;
+ 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:
- sc->sc_ntxbuf = 1;
- sc->sc_flags |= WI_FLAGS_HAS_DIVERSITY;
- 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;
}
/*
@@ -484,39 +438,18 @@
sc->sc_system_scale = 1;
sc->sc_cnfauthmode = IEEE80211_AUTH_OPEN;
sc->sc_roaming_mode = 1;
- sc->wi_channel = IEEE80211_CHAN_ANYC;
sc->sc_portnum = WI_DEFAULT_PORT;
sc->sc_authtype = WI_DEFAULT_AUTHTYPE;
- bzero(sc->sc_nodename, sizeof(sc->sc_nodename));
- sc->sc_nodelen = sizeof(WI_DEFAULT_NODENAME) - 1;
- bcopy(WI_DEFAULT_NODENAME, sc->sc_nodename, sc->sc_nodelen);
-
- bzero(sc->sc_net_name, sizeof(sc->sc_net_name));
- bcopy(WI_DEFAULT_NETNAME, sc->sc_net_name,
- sizeof(WI_DEFAULT_NETNAME) - 1);
-
- /*
- * Call MI attach routine.
- */
ieee80211_ifattach(ic);
- /* override state transition method */
- sc->sc_newstate = ic->ic_newstate;
- 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;
-
ic->ic_scan_start = wi_scan_start;
- ic->ic_scan_curchan = wi_scan_curchan;
- ic->ic_scan_mindwell = wi_scan_mindwell;
ic->ic_scan_end = wi_scan_end;
ic->ic_set_channel = wi_set_channel;
- ic->ic_node_alloc = wi_node_alloc;
- ic->ic_updateslot = wi_update_slot;
- ic->ic_reset = wi_reset;
- ieee80211_media_init(ic, wi_media_change, wi_media_status);
+ ic->ic_vap_create = wi_vap_create;
+ ic->ic_vap_delete = wi_vap_delete;
+ ic->ic_update_mcast = wi_update_mcast;
#if NBPFILTER > 0
bpfattach(ifp, DLT_IEEE802_11_RADIO,
@@ -558,11 +491,11 @@
wi_stop(ifp, 0);
WI_UNLOCK(sc);
-
#if NBPFILTER > 0
bpfdetach(ifp);
#endif
ieee80211_ifdetach(&sc->sc_ic);
+
bus_teardown_intr(dev, sc->irq, sc->wi_intrhand);
if_free(sc->sc_ifp);
wi_free(dev);
@@ -570,6 +503,75 @@
return (0);
}
+static struct ieee80211vap *
+wi_vap_create(struct ieee80211com *ic,
+ const char name[IFNAMSIZ], int unit, int opmode, int flags,
+ const uint8_t bssid[IEEE80211_ADDR_LEN],
+ const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+ struct wi_softc *sc = ic->ic_ifp->if_softc;
+ struct wi_vap *wvp;
+ struct ieee80211vap *vap;
+
+ if (!TAILQ_EMPTY(&ic->ic_vaps)) /* only one at a time */
+ return NULL;
+ wvp = (struct wi_vap *) malloc(sizeof(struct wi_vap),
+ M_80211_VAP, M_NOWAIT | M_ZERO);
+ if (wvp == NULL)
+ return NULL;
+ vap = &wvp->wv_vap;
+ ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
+
+ wvp->wv_recv_mgmt = vap->iv_recv_mgmt;
+ vap->iv_recv_mgmt = wi_recv_mgmt;
+ wvp->wv_newstate = vap->iv_newstate;
+ vap->iv_newstate = wi_newstate;
+ wvp->wv_key_alloc = vap->iv_key_alloc;
+ vap->iv_key_alloc = wi_key_alloc;
+ vap->iv_max_aid = WI_MAX_AID;
+
+ switch (opmode) {
+ case IEEE80211_M_STA:
+ sc->sc_porttype = WI_PORTTYPE_BSS;
+ break;
+ case IEEE80211_M_IBSS:
+ sc->sc_porttype = sc->sc_ibss_port;
+ break;
+ case IEEE80211_M_AHDEMO:
+ sc->sc_porttype = WI_PORTTYPE_ADHOC;
+ break;
+ case IEEE80211_M_HOSTAP:
+ sc->sc_porttype = WI_PORTTYPE_HOSTAP;
+ break;
+ case IEEE80211_M_MONITOR:
+ switch (sc->sc_firmware_type) {
+ case WI_LUCENT:
+ sc->sc_porttype = WI_PORTTYPE_ADHOC;
+ break;
+ case WI_INTERSIL:
+ sc->sc_porttype = WI_PORTTYPE_APSILENT;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* complete setup */
+ ieee80211_vap_attach(vap, ieee80211_media_change, wi_media_status);
+ ic->ic_opmode = opmode;
+ return vap;
+}
+
+static void
+wi_vap_delete(struct ieee80211vap *vap)
+{
+ struct wi_vap *wvp = WI_VAP(vap);
+
+ ieee80211_vap_detach(vap);
+ free(wvp, M_80211_VAP);
+}
+
void
wi_shutdown(device_t dev)
{
@@ -607,7 +609,6 @@
if (status & WI_EV_INFO)
wi_info_intr(sc);
if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0 &&
- (sc->sc_flags & WI_FLAGS_OUTRANGE) == 0 &&
!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
wi_start_locked(ifp);
@@ -625,13 +626,9 @@
struct wi_softc *sc = arg;
struct ifnet *ifp = sc->sc_ifp;
struct ieee80211com *ic = &sc->sc_ic;
- struct wi_joinreq join;
- struct ieee80211_channel *chan;
int i;
int error = 0, wasenabled;
-
-
if (sc->wi_gone)
return;
@@ -641,126 +638,26 @@
WI_LOCK(sc);
wi_reset(ifp);
- /* common 802.11 configuration */
- ic->ic_flags &= ~IEEE80211_F_IBSSON;
- sc->sc_flags &= ~WI_FLAGS_OUTRANGE;
- switch (ic->ic_opmode) {
- case IEEE80211_M_STA:
- wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_BSS);
- break;
- case IEEE80211_M_IBSS:
- wi_write_val(sc, WI_RID_PORTTYPE, sc->sc_ibss_port);
- ic->ic_flags |= IEEE80211_F_IBSSON;
- break;
- case IEEE80211_M_AHDEMO:
- wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_ADHOC);
- break;
- case IEEE80211_M_HOSTAP:
- /*
- * For PRISM cards, override the empty SSID, because in
- * HostAP mode the controller will lock up otherwise.
- */
- if (sc->sc_firmware_type == WI_INTERSIL &&
- ic->ic_des_ssid[0].len == 0) {
- ic->ic_des_ssid[0].ssid[0] = ' ';
- ic->ic_des_ssid[0].len = 1;
- }
- wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_HOSTAP);
- break;
- case IEEE80211_M_MONITOR:
- 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;
- case IEEE80211_M_WDS:
- /* XXXX */
- break;
- }
-
- /* Intersil interprets this RID as joining ESS even in IBSS mode */
- if (sc->sc_firmware_type == WI_LUCENT &&
- (ic->ic_flags & IEEE80211_F_IBSSON) && ic->ic_des_ssid[0].len > 0)
- wi_write_val(sc, WI_RID_CREATE_IBSS, 1);
- else
- wi_write_val(sc, WI_RID_CREATE_IBSS, 0);
- wi_write_val(sc, WI_RID_MAX_SLEEP, ic->ic_lintval);
- wi_write_ssid(sc, WI_RID_DESIRED_SSID, ic->ic_des_ssid[0].ssid,
- ic->ic_des_ssid[0].len);
- wi_write_val(sc, WI_RID_OWN_CHNL,
- ieee80211_chan2ieee(ic, ic->ic_bsschan));
- wi_write_ssid(sc, WI_RID_OWN_SSID, ic->ic_des_ssid[0].ssid,
- ic->ic_des_ssid[0].len);
-
- IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp));
- wi_write_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, IEEE80211_ADDR_LEN);
-
- if (ic->ic_caps & IEEE80211_C_PMGT)
- wi_write_val(sc, WI_RID_PM_ENABLED,
- (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0);
-
- /* not yet common 802.11 configuration */
+ wi_write_val(sc, WI_RID_PORTTYPE, sc->sc_porttype);
+ wi_write_val(sc, WI_RID_CREATE_IBSS, 0);
wi_write_val(sc, WI_RID_MAX_DATALEN, sc->sc_max_datalen);
- wi_write_val(sc, WI_RID_RTS_THRESH, ic->ic_rtsthreshold);
- if (sc->sc_flags & WI_FLAGS_HAS_FRAGTHR)
- wi_write_val(sc, WI_RID_FRAG_THRESH, ic->ic_fragthreshold);
-
- /* driver specific 802.11 configuration */
+#if 0
+ /* NB: for IEEE80211_BPF_NOACK */
+ wi_write_val(sc, WI_RID_ALT_RETRY_CNT, 0);
+#endif
if (sc->sc_flags & WI_FLAGS_HAS_SYSSCALE)
wi_write_val(sc, WI_RID_SYSTEM_SCALE, sc->sc_system_scale);
if (sc->sc_flags & WI_FLAGS_HAS_ROAMING)
wi_write_val(sc, WI_RID_ROAMING_MODE, sc->sc_roaming_mode);
if (sc->sc_flags & WI_FLAGS_HAS_MOR)
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) {
- wi_write_val(sc, WI_RID_OWN_BEACON_INT, ic->ic_bintval);
- wi_write_val(sc, WI_RID_BASIC_RATE, 0x03); /* 1, 2 */
- wi_write_val(sc, WI_RID_SUPPORT_RATE, 0x0f); /* 1, 2, 5.5, 11 */
- wi_write_val(sc, WI_RID_DTIM_PERIOD, ic->ic_dtim_period);
- }
-
- /*
- * Initialize promisc mode.
- * Being in the Host-AP mode causes a great
- * deal of pain if primisc mode is set.
- * Therefore we avoid confusing the firmware
- * and always reset promisc mode in Host-AP
- * mode. Host-AP sees all the packets anyway.
- */
- if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
- (ifp->if_flags & IFF_PROMISC) != 0) {
- wi_write_val(sc, WI_RID_PROMISC, 1);
- } else {
- wi_write_val(sc, WI_RID_PROMISC, 0);
- }
+ IEEE80211_ADDR_COPY(ic->ic_myaddr, IF_LLADDR(ifp));
+ wi_write_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, IEEE80211_ADDR_LEN);
- /* Configure WEP. */
- if (ic->ic_caps & IEEE80211_C_WEP) {
- sc->sc_cnfauthmode = ic->ic_bss->ni_authmode;
- wi_write_wep(sc);
- } else
- sc->sc_encryption = 0;
-
- /* Set multicast filter. */
- wi_write_multi(sc);
-
/* Allocate fids for the card */
- if (sc->sc_firmware_type != WI_SYMBOL || !wasenabled) {
+ if (!wasenabled) {
sc->sc_buflen = IEEE80211_MAX_LEN + sizeof(struct wi_frame);
- if (sc->sc_firmware_type == WI_SYMBOL)
- sc->sc_buflen = 1585; /* XXX */
for (i = 0; i < sc->sc_ntxbuf; i++) {
error = wi_alloc_fid(sc, sc->sc_buflen,
&sc->sc_txd[i].d_fid);
@@ -781,42 +678,14 @@
sc->sc_enabled = 1;
ifp->if_drv_flags |= IFF_DRV_RUNNING;
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
- if (ic->ic_opmode == IEEE80211_M_AHDEMO ||
- ic->ic_opmode == IEEE80211_M_IBSS ||
- ic->ic_opmode == IEEE80211_M_MONITOR ||
- ic->ic_opmode == IEEE80211_M_HOSTAP) {
- chan = (sc->wi_channel == IEEE80211_CHAN_ANYC) ?
- ic->ic_curchan : sc->wi_channel;
- ieee80211_create_ibss(ic, chan);
- }
+
/* Enable interrupts */
CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS);
+ WI_UNLOCK(sc);
- if (!wasenabled &&
- ic->ic_opmode == IEEE80211_M_HOSTAP &&
- sc->sc_firmware_type == WI_INTERSIL) {
- /* XXX: some card need to be re-enabled for hostap */
- wi_cmd(sc, WI_CMD_DISABLE | WI_PORT0, 0, 0, 0);
- wi_cmd(sc, WI_CMD_ENABLE | WI_PORT0, 0, 0, 0);
- }
-
- if (ic->ic_opmode == IEEE80211_M_STA &&
- ((ic->ic_flags & IEEE80211_F_DESBSSID) ||
- ic->ic_des_chan != IEEE80211_CHAN_ANYC)) {
- memset(&join, 0, sizeof(join));
- if (ic->ic_flags & IEEE80211_F_DESBSSID)
- IEEE80211_ADDR_COPY(&join.wi_bssid, ic->ic_des_bssid);
- if (ic->ic_des_chan != IEEE80211_CHAN_ANYC)
- join.wi_chan = htole16(
- ieee80211_chan2ieee(ic, ic->ic_des_chan));
- /* Lucent firmware does not support the JOIN RID. */
- if (sc->sc_firmware_type != WI_LUCENT)
- wi_write_rid(sc, WI_RID_JOIN_REQ, &join, sizeof(join));
- }
+ ieee80211_start_all(ic);
callout_reset(&sc->sc_watchdog, hz, wi_watchdog, sc);
-
- WI_UNLOCK(sc);
return;
out:
if (error) {
@@ -832,11 +701,7 @@
wi_stop(struct ifnet *ifp, int disable)
{
struct wi_softc *sc = ifp->if_softc;
- struct ieee80211com *ic = &sc->sc_ic;
-
- ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
- DELAY(100000);
WI_LOCK(sc);
if (sc->sc_enabled && !sc->wi_gone) {
CSR_WRITE_2(sc, WI_INT_EN, 0);
@@ -844,26 +709,177 @@
if (disable)
sc->sc_enabled = 0;
} else if (sc->wi_gone && disable) /* gone --> not enabled */
- sc->sc_enabled = 0;
+ sc->sc_enabled = 0;
callout_stop(&sc->sc_watchdog); /* XXX drain */
sc->sc_tx_timer = 0;
- sc->sc_scan_timer = 0;
sc->sc_false_syns = 0;
- sc->sc_naps = 0;
+
ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE | IFF_DRV_RUNNING);
WI_UNLOCK(sc);
}
static void
+wi_set_channel(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct wi_softc *sc = ifp->if_softc;
+
+ WI_LOCK(sc);
+ wi_write_val(sc, WI_RID_OWN_CHNL,
+ ieee80211_chan2ieee(ic, ic->ic_curchan));
+
+#if NBPFILTER > 0
+ sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
+ htole16(ic->ic_curchan->ic_freq);
+ sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags =
+ htole16(ic->ic_curchan->ic_flags);
+#endif
+
+ if ((ic->ic_flags & IEEE80211_F_SCAN) == 0 &&
+ ic->ic_opmode == IEEE80211_M_HOSTAP &&
+ sc->sc_firmware_type == WI_INTERSIL) {
+ /* XXX: some cards need to be re-enabled */
+ wi_cmd(sc, WI_CMD_DISABLE | WI_PORT0, 0, 0, 0);
+ wi_cmd(sc, WI_CMD_ENABLE | WI_PORT0, 0, 0, 0);
+ }
+ WI_UNLOCK(sc);
+}
+
+static void
+wi_scan_start(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct wi_softc *sc = ifp->if_softc;
+ struct ieee80211_scan_state *ss = ic->ic_scan;
+
+ WI_LOCK(sc);
+ /*
+ * Switch device to monitor mode.
+ */
+ 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);
+
+ ss->ss_mindwell = ss->ss_maxdwell = msecs_to_ticks(400); /* 400ms */
+ WI_UNLOCK(sc);
+
+}
+
+static void
+wi_scan_end(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct wi_softc *sc = ifp->if_softc;
+
+ WI_LOCK(sc);
+ wi_cmd(sc, WI_CMD_DEBUG, 0, 0, 0);
+ wi_write_val(sc, WI_RID_PORTTYPE, sc->sc_porttype);
+ WI_UNLOCK(sc);
+}
+
+static void
+wi_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
+ int subtype, int rssi, int noise, u_int32_t rstamp)
+{
+ struct ieee80211vap *vap = ni->ni_vap;
+
+ switch (subtype) {
+ case IEEE80211_FC0_SUBTYPE_AUTH:
+ case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
+ case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
+ /* NB: filter frames that trigger state changes */
+ return;
+ }
+ WI_VAP(vap)->wv_recv_mgmt(ni, m, subtype, rssi, noise, rstamp);
+}
+
+static int
+wi_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+ struct ifnet *ifp = ic->ic_ifp;
+ struct wi_softc *sc = ifp->if_softc;
+ int error;
+
+ DPRINTF(("%s: %s -> %s\n", __func__,
+ ieee80211_state_name[vap->iv_state],
+ ieee80211_state_name[nstate]));
+
+ if (nstate == IEEE80211_S_AUTH) {
+ struct ieee80211_node *bss = vap->iv_bss;
+
+ wi_write_ssid(sc, WI_RID_DESIRED_SSID,
+ bss->ni_essid, bss->ni_esslen);
+ /* Lucent firmware does not support the JOIN RID. */
+ if (sc->sc_firmware_type == WI_INTERSIL) {
+ struct wi_joinreq join;
+
+ memset(&join, 0, sizeof(join));
+ IEEE80211_ADDR_COPY(&join.wi_bssid, bss->ni_bssid);
+ join.wi_chan = htole16(
+ ieee80211_chan2ieee(ic, bss->ni_chan));
+ wi_write_rid(sc, WI_RID_JOIN_REQ, &join, sizeof(join));
+ } else {
+ wi_write_val(sc, WI_RID_CREATE_IBSS, 0);
+ }
+ /* NB: don't go through 802.11 layer, it'll send auth frame */
+ vap->iv_state = nstate;
+ return EINPROGRESS;
+ }
+
+ error = WI_VAP(vap)->wv_newstate(vap, nstate, arg);
+
+ if (nstate == IEEE80211_S_RUN && vap->iv_state != IEEE80211_S_RUN) {
+ if (vap->iv_opmode == IEEE80211_M_MONITOR)
+ wi_cmd(sc, WI_CMD_DEBUG | (WI_TEST_MONITOR << 8), 0, 0, 0);
+ wi_write_val(sc, WI_RID_MAX_SLEEP, ic->ic_lintval);
+ if (ic->ic_caps & IEEE80211_C_PMGT)
+ wi_write_val(sc, WI_RID_PM_ENABLED,
+ (vap->iv_flags & IEEE80211_F_PMGTON) ? 1 : 0);
+ wi_write_val(sc, WI_RID_RTS_THRESH, vap->iv_rtsthreshold);
+ if (sc->sc_flags & WI_FLAGS_HAS_FRAGTHR)
+ wi_write_val(sc, WI_RID_FRAG_THRESH,
+ vap->iv_fragthreshold);
+ wi_write_txrate(sc, vap);
+
+ /* Configure WEP. */
+ if (ic->ic_caps & IEEE80211_C_WEP) {
+ sc->sc_cnfauthmode = vap->iv_bss->ni_authmode;
+ wi_write_wep(sc, vap);
+ } else
+ sc->sc_encryption = 0;
+
+ if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
+ sc->sc_firmware_type == WI_INTERSIL) {
+ wi_write_ssid(sc, WI_RID_OWN_SSID,
+ vap->iv_des_ssid[0].ssid, vap->iv_des_ssid[0].len);
+ wi_write_val(sc, WI_RID_OWN_BEACON_INT, ic->ic_bintval);
+ wi_write_val(sc, WI_RID_BASIC_RATE, 0x03); /* 1, 2 */
+ wi_write_val(sc, WI_RID_SUPPORT_RATE, 0x0f); /* 1, 2, 5.5, 11 */
+ wi_write_val(sc, WI_RID_DTIM_PERIOD, vap->iv_dtim_period);
+ /* XXX: some card need to be re-enabled for hostap */
+ wi_cmd(sc, WI_CMD_DISABLE | WI_PORT0, 0, 0, 0);
+ wi_cmd(sc, WI_CMD_ENABLE | WI_PORT0, 0, 0, 0);
+ }
+ return WI_VAP(vap)->wv_newstate(vap, nstate, arg);
+ }
+ return 0;
+}
+
+static void
wi_start_locked(struct ifnet *ifp)
{
struct wi_softc *sc = ifp->if_softc;
- struct ieee80211com *ic = &sc->sc_ic;
struct ieee80211_node *ni;
struct ieee80211_frame *wh;
- struct ether_header *eh;
struct mbuf *m0;
struct wi_frame frmhdr;
int cur;
@@ -872,83 +888,37 @@
if (sc->wi_gone)
return;
- if (sc->sc_flags & WI_FLAGS_OUTRANGE)
- return;
memset(&frmhdr, 0, sizeof(frmhdr));
cur = sc->sc_txnext;
for (;;) {
- IF_POLL(&ic->ic_mgtq, m0);
- if (m0 != NULL) {
- if (sc->sc_txd[cur].d_len != 0) {
- ifp->if_drv_flags |= IFF_DRV_OACTIVE;
- break;
- }
- IF_DEQUEUE(&ic->ic_mgtq, m0);
- /*
- * Hack! The referenced node pointer is in the
- * rcvif field of the packet header. This is
- * placed there by ieee80211_mgmt_output because
- * we need to hold the reference with the frame
- * and there's no other way (other than packet
- * tags which we consider too expensive to use)
- * to pass it along.
- */
- ni = (struct ieee80211_node *) m0->m_pkthdr.rcvif;
- m0->m_pkthdr.rcvif = NULL;
+ IFQ_DRV_DEQUEUE(&ifp->if_snd, m0);
+ if (m0 == NULL)
+ break;
+ if (sc->sc_txd[cur].d_len != 0) {
+ IFQ_DRV_PREPEND(&ifp->if_snd, m0);
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ break;
+ }
+ /* NB: copy before 802.11 header is prepended */
+ m_copydata(m0, 0, ETHER_HDR_LEN,
+ (caddr_t)&frmhdr.wi_ehdr);
- 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 *);
- } else {
- if (ic->ic_state != IEEE80211_S_RUN)
- break;
- IFQ_DRV_DEQUEUE(&ifp->if_snd, m0);
- if (m0 == NULL)
- break;
- if (sc->sc_txd[cur].d_len != 0) {
- IFQ_DRV_PREPEND(&ifp->if_snd, m0);
- ifp->if_drv_flags |= IFF_DRV_OACTIVE;
- break;
- }
- if (m0->m_len < sizeof(struct ether_header) &&
- (m0 = m_pullup(m0, sizeof(struct ether_header))) == NULL) {
- ifp->if_oerrors++;
- continue;
- }
- eh = mtod(m0, struct ether_header *);
- ni = ieee80211_find_txnode(ic, eh->ether_dhost);
- if (ni == NULL) {
- m_freem(m0);
- continue;
- }
- ifp->if_opackets++;
- m_copydata(m0, 0, ETHER_HDR_LEN,
- (caddr_t)&frmhdr.wi_ehdr);
-#if NBPFILTER > 0
- BPF_MTAP(ifp, m0);
-#endif
-
- m0 = ieee80211_encap(ic, m0, ni);
- if (m0 == NULL) {
- ifp->if_oerrors++;
- ieee80211_free_node(ni);
- continue;
- }
- wh = mtod(m0, struct ieee80211_frame *);
+ ni = (struct ieee80211_node *) m0->m_pkthdr.rcvif;
+ m0 = ieee80211_encap(ni, m0);
+ if (m0 == NULL) {
+ ifp->if_oerrors++;
+ ieee80211_free_node(ni);
+ continue;
}
-#if NBPFILTER > 0
- if (bpf_peers_present(ic->ic_rawbpf))
- bpf_mtap(ic->ic_rawbpf, m0);
-#endif
+ wh = mtod(m0, struct ieee80211_frame *);
frmhdr.wi_tx_ctl = htole16(WI_ENC_TX_802_11|WI_TXCNTL_TX_EX);
/* XXX check key for SWCRYPT instead of using operating mode */
if ((wh->i_fc[1] & IEEE80211_FC1_WEP) &&
(sc->sc_encryption & HOST_ENCRYPT)) {
struct ieee80211_key *k;
- k = ieee80211_crypto_encap(ic, ni, m0);
+ k = ieee80211_crypto_encap(ni, m0);
if (k == NULL) {
ieee80211_free_node(ni);
m_freem(m0);
@@ -958,8 +928,7 @@
}
#if NBPFILTER > 0
if (bpf_peers_present(ifp->if_bpf)) {
- sc->sc_tx_th.wt_rate =
- ni->ni_rates.rs_rates[ni->ni_txrate];
+ sc->sc_tx_th.wt_rate = ni->ni_txrate;
bpf_mtap2(ifp->if_bpf,
&sc->sc_tx_th, sc->sc_tx_th_len, m0);
}
@@ -973,7 +942,9 @@
ieee80211_free_node(ni);
if (wi_start_tx(ifp, &frmhdr, m0))
continue;
+
sc->sc_txnext = cur = (cur + 1) % sc->sc_ntxbuf;
+ ifp->if_opackets++;
}
}
@@ -1033,11 +1004,6 @@
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) {
@@ -1052,10 +1018,6 @@
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);
@@ -1066,7 +1028,7 @@
(params && (params->ibp_flags & IEEE80211_BPF_CRYPTO))) {
struct ieee80211_key *k;
- k = ieee80211_crypto_encap(ic, ni, m0);
+ k = ieee80211_crypto_encap(ni, m0);
if (k == NULL) {
rc = ENOMEM;
goto out;
@@ -1076,8 +1038,7 @@
}
#if NBPFILTER > 0
if (bpf_peers_present(ifp->if_bpf)) {
- sc->sc_tx_th.wt_rate =
- ni->ni_rates.rs_rates[ni->ni_txrate];
+ sc->sc_tx_th.wt_rate = ni->ni_txrate;
bpf_mtap2(ifp->if_bpf, &sc->sc_tx_th, sc->sc_tx_th_len, m0);
}
#endif
@@ -1107,30 +1068,20 @@
static int
wi_reset(struct ifnet *ifp)
{
+#define WI_INIT_TRIES 3
>>> TRUNCATED FOR MAIL (1000 lines) <<<
More information about the p4-projects
mailing list