From owner-p4-projects@FreeBSD.ORG Tue Mar 18 19:23:32 2008 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id C9D7F106567B; Tue, 18 Mar 2008 19:23:31 +0000 (UTC) Delivered-To: perforce@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 828D21065670 for ; Tue, 18 Mar 2008 19:23:31 +0000 (UTC) (envelope-from sam@freebsd.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 848378FC1C for ; Tue, 18 Mar 2008 19:23:31 +0000 (UTC) (envelope-from sam@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.1/8.14.1) with ESMTP id m2IJNVRA083005 for ; Tue, 18 Mar 2008 19:23:31 GMT (envelope-from sam@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.1/8.14.1/Submit) id m2IJNV4c083003 for perforce@freebsd.org; Tue, 18 Mar 2008 19:23:31 GMT (envelope-from sam@freebsd.org) Date: Tue, 18 Mar 2008 19:23:31 GMT Message-Id: <200803181923.m2IJNV4c083003@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to sam@freebsd.org using -f From: Sam Leffler To: Perforce Change Reviews Cc: Subject: PERFORCE change 138040 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 18 Mar 2008 19:23:32 -0000 http://perforce.freebsd.org/chv.cgi?CH=138040 Change 138040 by sam@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 . All rights reserved. @@ -64,7 +62,6 @@ #include __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 #include +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) <<<