PERFORCE change 140035 for review

Sam Leffler sam at FreeBSD.org
Mon Apr 14 17:27:46 UTC 2008


http://perforce.freebsd.org/chv.cgi?CH=140035

Change 140035 by sam at sam_ebb on 2008/04/14 17:27:22

	checkpoint; associates

Affected files ...

.. //depot/projects/vap/sys/dev/ipw/if_ipw.c#12 edit
.. //depot/projects/vap/sys/dev/ipw/if_ipwvar.h#9 edit

Differences ...

==== //depot/projects/vap/sys/dev/ipw/if_ipw.c#12 (text+ko) ====

@@ -118,6 +118,10 @@
 static int	ipw_newstate(struct ieee80211vap *, enum ieee80211_state, int);
 static uint16_t	ipw_read_prom_word(struct ipw_softc *, uint8_t);
 static void	ipw_rx_cmd_intr(struct ipw_softc *, struct ipw_soft_buf *);
+static void	ipw_assocsuccess(void *, int);
+static void	ipw_assocfailed(void *, int);
+static void	ipw_scandone(void *, int);
+static void	ipw_bmiss(void *, int);
 static void	ipw_rx_newstate_intr(struct ipw_softc *, struct ipw_soft_buf *);
 static void	ipw_rx_data_intr(struct ipw_softc *, struct ipw_status *,
 		    struct ipw_soft_bd *, struct ipw_soft_buf *);
@@ -130,6 +134,8 @@
 static int	ipw_cmd(struct ipw_softc *, uint32_t, void *, uint32_t);
 static int	ipw_tx_start(struct ifnet *, struct mbuf *,
 		    struct ieee80211_node *);
+static int	ipw_raw_xmit(struct ieee80211_node *, struct mbuf *,
+		    const struct ieee80211_bpf_params *);
 static void	ipw_start(struct ifnet *);
 static void	ipw_start_locked(struct ifnet *);
 static void	ipw_watchdog(void *);
@@ -142,12 +148,10 @@
 static int	ipw_load_firmware(struct ipw_softc *, const char *, int);
 static int	ipw_config(struct ipw_softc *);
 static void	ipw_assoc_task(void *, int);
-static int	ipw_auth_and_assoc(struct ipw_softc *);
 static void	ipw_disassoc_task(void *, int);
-static int	ipw_disassociate(struct ipw_softc *);
 static void	ipw_init_task(void *, int);
 static void	ipw_init(void *);
-static void	ipw_init_locked(struct ipw_softc *, int);
+static void	ipw_init_locked(struct ipw_softc *);
 static void	ipw_stop(void *);
 static void	ipw_stop_locked(struct ipw_softc *);
 static int	ipw_sysctl_stats(SYSCTL_HANDLER_ARGS);
@@ -236,8 +240,7 @@
 
 	TASK_INIT(&sc->sc_init_task, 0, ipw_init_task, sc);
 	TASK_INIT(&sc->sc_scan_task, 0, ipw_scan_task, sc);
-	TASK_INIT(&sc->sc_assoc_task, 0, ipw_assoc_task, sc);
-	TASK_INIT(&sc->sc_disassoc_task, 0, ipw_disassoc_task, sc);
+	TASK_INIT(&sc->sc_bmiss_task, 0, ipw_bmiss, sc);
 	callout_init_mtx(&sc->sc_wdtimer, &sc->sc_mtx, 0);
 
 	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
@@ -267,23 +270,23 @@
 	    RF_ACTIVE | RF_SHAREABLE);
 	if (sc->irq == NULL) {
 		device_printf(dev, "could not allocate interrupt resource\n");
-		goto fail;
+		goto fail1;
 	}
 
 	if (ipw_reset(sc) != 0) {
 		device_printf(dev, "could not reset adapter\n");
-		goto fail;
+		goto fail2;
 	}
 
 	if (ipw_dma_alloc(sc) != 0) {
 		device_printf(dev, "could not allocate DMA resources\n");
-		goto fail;
+		goto fail2;
 	}
 
 	ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
 	if (ifp == NULL) {
 		device_printf(dev, "can not if_alloc()\n");
-		goto fail;
+		goto fail3;
 	}
 	ic = ifp->if_l2com;
 
@@ -298,6 +301,7 @@
 	IFQ_SET_READY(&ifp->if_snd);
 
 	ic->ic_ifp = ifp;
+	ic->ic_opmode = IEEE80211_M_STA;
 	ic->ic_phytype = IEEE80211_T_DS;
 
 	/* set device capabilities */
@@ -342,6 +346,7 @@
 	ic->ic_set_channel = ipw_set_channel;
 	ic->ic_scan_curchan = ipw_scan_curchan;
 	ic->ic_scan_mindwell = ipw_scan_mindwell;
+	ic->ic_raw_xmit = ipw_raw_xmit;
 
 	ic->ic_vap_create = ipw_vap_create;
 	ic->ic_vap_delete = ipw_vap_delete;
@@ -377,15 +382,23 @@
 	    NULL, ipw_intr, sc, &sc->sc_ih);
 	if (error != 0) {
 		device_printf(dev, "could not set up interrupt\n");
-		goto fail;
+		goto fail4;
 	}
 
 	if (bootverbose)
 		ieee80211_announce(ic);
 
 	return 0;
-
-fail:	ipw_detach(dev);
+fail4:
+	if_free(ifp);
+fail3:
+	ipw_release(sc);
+fail2:
+	bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
+fail1:
+	bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem);
+fail:
+	mtx_destroy(&sc->sc_mtx);
 	return ENXIO;
 }
 
@@ -397,29 +410,23 @@
 	struct ieee80211com *ic = ifp->if_l2com;
 
 	ipw_stop(sc);
+
+	bpfdetach(ifp);
+	ieee80211_ifdetach(ic);
+
 	callout_drain(&sc->sc_wdtimer);
 	taskqueue_drain(taskqueue_fast, &sc->sc_init_task);
 	taskqueue_drain(taskqueue_fast, &sc->sc_scan_task);
-	taskqueue_drain(taskqueue_fast, &sc->sc_assoc_task);
-	taskqueue_drain(taskqueue_fast, &sc->sc_disassoc_task);
+	taskqueue_drain(taskqueue_fast, &sc->sc_bmiss_task);
 
-	if (ifp != NULL) {
-		bpfdetach(ifp);
-		ieee80211_ifdetach(ic);
-	}
-
 	ipw_release(sc);
 
-	if (sc->irq != NULL) {
-		bus_teardown_intr(dev, sc->irq, sc->sc_ih);
-		bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
-	}
+	bus_teardown_intr(dev, sc->irq, sc->sc_ih);
+	bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq);
 
-	if (sc->mem != NULL)
-		bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem);
+	bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem);
 
-	if (ifp != NULL)
-		if_free(ifp);
+	if_free(ifp);
 
 	if (sc->sc_firmware != NULL) {
 		firmware_put(sc->sc_firmware, FIRMWARE_UNLOAD);
@@ -437,16 +444,77 @@
 	const uint8_t bssid[IEEE80211_ADDR_LEN],
 	const uint8_t mac[IEEE80211_ADDR_LEN])
 {
+	struct ifnet *ifp = ic->ic_ifp;
+	struct ipw_softc *sc = ifp->if_softc;
 	struct ipw_vap *ivp;
 	struct ieee80211vap *vap;
+	const struct firmware *fp;
+	const struct ipw_firmware_hdr *hdr;
+	const char *imagename;
 
 	if (!TAILQ_EMPTY(&ic->ic_vaps))		/* only one at a time */
 		return NULL;
+
+	switch (opmode) {
+	case IEEE80211_M_STA:
+		imagename = "ipw_bss";
+		break;
+	case IEEE80211_M_IBSS:
+		imagename = "ipw_ibss";
+		break;
+	case IEEE80211_M_MONITOR:
+		imagename = "ipw_monitor";
+		break;
+	default:
+		return NULL;
+	}
+
+	/*
+	 * Load firmware image using the firmware(9) subsystem.  Doing
+	 * this unlocked is ok since we're single-threaded by the
+	 * 802.11 layer.
+	 */
+	if (sc->sc_firmware == NULL ||
+	    strcmp(sc->sc_firmware->name, imagename) != 0) {
+		if (sc->sc_firmware != NULL)
+			firmware_put(sc->sc_firmware, FIRMWARE_UNLOAD);
+		sc->sc_firmware = firmware_get(imagename);
+	}
+	if (sc->sc_firmware == NULL) {
+		device_printf(sc->sc_dev,
+		    "could not load firmware image '%s'\n", imagename);
+		return NULL;
+	}
+	fp = sc->sc_firmware;
+	if (fp->datasize < sizeof *hdr) {
+		device_printf(sc->sc_dev,
+		    "firmware image too short %zu\n", fp->datasize);
+		firmware_put(sc->sc_firmware, FIRMWARE_UNLOAD);
+		sc->sc_firmware = NULL;
+		return NULL;
+	}
+	hdr = (const struct ipw_firmware_hdr *)fp->data;
+	if (fp->datasize < sizeof *hdr + le32toh(hdr->mainsz) +
+	    le32toh(hdr->ucodesz)) {
+		device_printf(sc->sc_dev,
+		    "firmware image too short %zu\n", fp->datasize);
+		firmware_put(sc->sc_firmware, FIRMWARE_UNLOAD);
+		sc->sc_firmware = NULL;
+		return NULL;
+	}
+
 	ivp = (struct ipw_vap *) malloc(sizeof(struct ipw_vap),
 	    M_80211_VAP, M_NOWAIT | M_ZERO);
 	if (ivp == NULL)
 		return NULL;
 	vap = &ivp->vap;
+
+	TASK_INIT(&ivp->assoc_task, 0, ipw_assoc_task, vap);
+	TASK_INIT(&ivp->disassoc_task, 0, ipw_disassoc_task, vap);
+	TASK_INIT(&ivp->assoc_success_task, 0, ipw_assocsuccess, vap);
+	TASK_INIT(&ivp->assoc_failed_task, 0, ipw_assocfailed, vap);
+	TASK_INIT(&ivp->scandone_task, 0, ipw_scandone, vap);
+
 	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
 	/* override with driver methods */
 	ivp->newstate = vap->iv_newstate;
@@ -786,7 +854,7 @@
 	pci_write_config(dev, 0x41, 0, 1);
 
 	if (ifp->if_flags & IFF_UP) {
-		ipw_init_locked(sc, 0);
+		ipw_init_locked(sc);
 		if (ifp->if_drv_flags & IFF_DRV_RUNNING)
 			ipw_start_locked(ifp);
 	}
@@ -848,30 +916,34 @@
 			 * AUTH -> RUN transition and we want to do nothing.
 			 * This is all totally bogus and needs to be redone.
 			 */
-			if (vap->iv_state == IEEE80211_S_SCAN)
-				taskqueue_enqueue_fast(taskqueue_fast,
-				    &sc->sc_assoc_task);
+			if (vap->iv_state == IEEE80211_S_SCAN) {
+				taskqueue_enqueue(taskqueue_swi,
+				    &IPW_VAP(vap)->assoc_task);
+				return EINPROGRESS;
+			}
 		}
 		break;
 
 	case IEEE80211_S_INIT:
 		if (sc->flags & IPW_FLAG_ASSOCIATED)
-			taskqueue_enqueue_fast(taskqueue_fast,
-			    &sc->sc_disassoc_task);
+			taskqueue_enqueue(taskqueue_swi,
+			    &IPW_VAP(vap)->disassoc_task);
 		break;
 
 	case IEEE80211_S_AUTH:
-		taskqueue_enqueue_fast(taskqueue_fast, &sc->sc_assoc_task);
-		break;
+		taskqueue_enqueue(taskqueue_swi, &IPW_VAP(vap)->assoc_task);
+		return EINPROGRESS;
 
 	case IEEE80211_S_ASSOC:
 		/*
 		 * If we are not transitioning from AUTH the resend the
 		 * association request.
 		 */
-		if (vap->iv_state != IEEE80211_S_AUTH)
-			taskqueue_enqueue_fast(taskqueue_fast,
-			    &sc->sc_assoc_task);
+		if (vap->iv_state != IEEE80211_S_AUTH) {
+			taskqueue_enqueue(taskqueue_swi,
+			    &IPW_VAP(vap)->assoc_task);
+			return EINPROGRESS;
+		}
 		break;
 
 	default:
@@ -954,6 +1026,38 @@
 }
 
 static void
+ipw_assocsuccess(void *arg, int npending)
+{
+	struct ieee80211vap *vap = arg;
+
+	ieee80211_new_state(vap, IEEE80211_S_RUN, -1);
+}
+
+static void
+ipw_assocfailed(void *arg, int npending)
+{
+	struct ieee80211vap *vap = arg;
+
+	ieee80211_new_state(vap, IEEE80211_S_SCAN, -1);
+}
+
+static void
+ipw_scandone(void *arg, int npending)
+{
+	struct ieee80211vap *vap = arg;
+
+	ieee80211_scan_done(vap);
+}
+
+static void
+ipw_bmiss(void *arg, int npending)
+{
+	struct ieee80211com *ic = arg;
+
+	ieee80211_beacon_miss(ic);
+}
+
+static void
 ipw_rx_newstate_intr(struct ipw_softc *sc, struct ipw_soft_buf *sbuf)
 {
 #define	IEEESTATE(vap)	ieee80211_state_name[vap->iv_state]
@@ -970,13 +1074,16 @@
 	case IPW_STATE_ASSOCIATED:
 		DPRINTFN(2, ("Association succeeded (%s flags 0x%x)\n",
 			IEEESTATE(vap), sc->flags));
+		/* XXX suppress state change in case the fw auto-associates */
+		if ((sc->flags & IPW_FLAG_ASSOCIATING) == 0) {
+			DPRINTF(("Unexpected association (%s, flags 0x%x)\n",
+				IEEESTATE(vap), sc->flags));
+			break;
+		}
+		sc->flags &= ~IPW_FLAG_ASSOCIATING;
 		sc->flags |= IPW_FLAG_ASSOCIATED;
-		/* XXX suppress state change in case the fw auto-associates */
-		if (vap->iv_state != IEEE80211_S_ASSOC) {
-			DPRINTF(("Unexpected association (state %u)\n",
-				vap->iv_state));
-		} else
-			ieee80211_new_state(vap, IEEE80211_S_RUN, -1);
+		taskqueue_enqueue(taskqueue_swi,
+		    &IPW_VAP(vap)->assoc_success_task);
 		break;
 
 	case IPW_STATE_SCANNING:
@@ -988,8 +1095,10 @@
 		 * scan and we would treat it as a beacon miss if
 		 * we checked the 802.11 layer state.
 		 */
-		if (sc->flags & IPW_FLAG_ASSOCIATED)
-			ieee80211_beacon_miss(ic);
+		if (sc->flags & IPW_FLAG_ASSOCIATED) {
+			/* XXX probably need to issue disassoc to fw */
+			taskqueue_enqueue(taskqueue_swi, &sc->sc_bmiss_task);
+		}
 		break;
 
 	case IPW_STATE_SCAN_COMPLETE:
@@ -1000,14 +1109,15 @@
 		 * around this by marking the HACK flag and skipping
 		 * the first scan complete event.
 		*/
+		DPRINTFN(3, ("Scan complete (%s flags 0x%x)\n",
+			    IEEESTATE(vap), sc->flags));
 		if (sc->flags & IPW_FLAG_HACK) {
 			sc->flags &= ~IPW_FLAG_HACK;
 			break;
 		}
-		DPRINTFN(3, ("Scan complete (%s flags 0x%x)\n",
-			    IEEESTATE(vap), sc->flags));
 		if (sc->flags & IPW_FLAG_SCANNING) {
-			ieee80211_scan_done(vap);
+			taskqueue_enqueue(taskqueue_swi,
+			    &IPW_VAP(vap)->scandone_task);
 			sc->flags &= ~IPW_FLAG_SCANNING;
 			sc->sc_scan_timer = 0;
 		}
@@ -1016,21 +1126,25 @@
 	case IPW_STATE_ASSOCIATION_LOST:
 		DPRINTFN(2, ("Association lost (%s flags 0x%x)\n",
 			IEEESTATE(vap), sc->flags));
-		sc->flags &= ~IPW_FLAG_ASSOCIATED;
+		sc->flags &= ~(IPW_FLAG_ASSOCIATING | IPW_FLAG_ASSOCIATED);
 		if (vap->iv_state == IEEE80211_S_RUN)
-			ieee80211_new_state(vap, IEEE80211_S_SCAN, -1);
+			taskqueue_enqueue(taskqueue_swi,
+			    &IPW_VAP(vap)->assoc_failed_task);
 		break;
 
 	case IPW_STATE_DISABLED:
+		/* XXX? is this right? */
+		sc->flags &= ~(IPW_FLAG_HACK | IPW_FLAG_SCANNING | 
+		    IPW_FLAG_ASSOCIATING | IPW_FLAG_ASSOCIATED);
 		DPRINTFN(2, ("Firmware disabled (%s flags 0x%x)\n",
 			IEEESTATE(vap), sc->flags));
 		break;
 
 	case IPW_STATE_RADIO_DISABLED:
-		DPRINTFN(2, ("Radio off (%s flags 0x%x)\n",
-			IEEESTATE(vap), sc->flags));
-		vap->iv_ifp->if_flags &= ~IFF_UP;	/* XXX */
+		device_printf(sc->sc_dev, "radio turned off\n");
+		ieee80211_notify_radio(ic, 0);
 		ipw_stop_locked(sc);
+		/* XXX start polling thread to detect radio on */
 		break;
 
 	default:
@@ -1199,9 +1313,6 @@
 static void
 ipw_rx_intr(struct ipw_softc *sc)
 {
-	struct ifnet *ifp = sc->sc_ifp;
-	struct ieee80211com *ic = ifp->if_l2com;
-	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
 	struct ipw_status *status;
 	struct ipw_soft_bd *sbd;
 	struct ipw_soft_buf *sbuf;
@@ -1236,11 +1347,7 @@
 		case IPW_STATUS_CODE_NOTIFICATION:
 			DPRINTFN(2, ("notification status, len %u flags 0x%x\n",
 			    le32toh(status->len), status->flags));
-			if (vap->iv_state == IEEE80211_S_AUTH) {
-				/* XXX assume auth notification */
-				ieee80211_node_authorize(vap->iv_bss);
-				ieee80211_new_state(vap, IEEE80211_S_ASSOC, -1);
-			}
+			/* XXX maybe drive state machine AUTH->ASSOC? */
 			break;
 
 		default:
@@ -1352,7 +1459,7 @@
 
 	if (r & (IPW_INTR_FATAL_ERROR | IPW_INTR_PARITY_ERROR)) {
 		device_printf(sc->sc_dev, "firmware error\n");
-		taskqueue_enqueue_fast(taskqueue_fast, &sc->sc_init_task);
+		taskqueue_enqueue(taskqueue_swi, &sc->sc_init_task);
 		r = 0;	/* don't process more interrupts */
 	}
 
@@ -1440,6 +1547,8 @@
 	bus_addr_t physaddr;
 	int error;
 
+	IPW_LOCK_ASSERT(sc);
+
 	if (sc->flags & IPW_FLAG_BUSY) {
 		device_printf(sc->sc_dev, "%s: %s not sent, busy\n",
 			__func__, ipw_cmdname(type));
@@ -1652,6 +1761,16 @@
 	return 0;
 }
 
+static int
+ipw_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
+	const struct ieee80211_bpf_params *params)
+{
+	/* no support; just discard */
+	m_freem(m);
+	ieee80211_free_node(ni);
+	return 0;
+}
+
 static void
 ipw_start(struct ifnet *ifp)
 {
@@ -1710,8 +1829,7 @@
 		if (--sc->sc_tx_timer == 0) {
 			if_printf(ifp, "device timeout\n");
 			ifp->if_oerrors++;
-			taskqueue_enqueue_fast(taskqueue_fast,
-			    &sc->sc_init_task);
+			taskqueue_enqueue(taskqueue_swi, &sc->sc_init_task);
 		}
 	}
 	if (sc->sc_scan_timer > 0) {
@@ -1737,17 +1855,17 @@
 	int error = 0;
 	IPW_LOCK_DECL;
 
-	IPW_LOCK(sc);
-
 	switch (cmd) {
 	case SIOCSIFFLAGS:
+		IPW_LOCK(sc);
 		if (ifp->if_flags & IFF_UP) {
 			if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
-				ipw_init_locked(sc, 0);
+				ipw_init_locked(sc);
 		} else {
 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
 				ipw_stop_locked(sc);
 		}
+		IPW_UNLOCK(sc);
 		break;
 	case SIOCGIFMEDIA:
 	case SIOCSIFMEDIA:
@@ -1756,9 +1874,6 @@
 	default:
 		error = ether_ioctl(ifp, cmd, data);
 	}
-
-	IPW_UNLOCK(sc);
-
 	return error;
 }
 
@@ -2146,146 +2261,50 @@
 	return error;
 }
 
-static int
-ipw_config(struct ipw_softc *sc)
+static void
+ipw_assoc_task(void *context, int pending)
 {
-	struct ifnet *ifp = sc->sc_ifp;
+	struct ieee80211vap *vap = context;
+	struct ifnet *ifp = vap->iv_ic->ic_ifp;
 	struct ieee80211com *ic = ifp->if_l2com;
-	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
+	struct ipw_softc *sc = ifp->if_softc;
+	struct ieee80211_node *ni = vap->iv_bss;
 	struct ipw_security security;
-	struct ipw_configuration config;
 	uint32_t data;
 	int error;
+	IPW_LOCK_DECL;
 
+	IPW_LOCK(sc);
 	error = ipw_disable(sc);
 	if (error != 0)
-		return error;
+		goto done;
 
-	switch (ic->ic_opmode) {
-	case IEEE80211_M_STA:
-	case IEEE80211_M_HOSTAP:
-	case IEEE80211_M_WDS:		/* XXX */
-		data = htole32(IPW_MODE_BSS);
-		break;
-	case IEEE80211_M_IBSS:
-	case IEEE80211_M_AHDEMO:
-		data = htole32(IPW_MODE_IBSS);
-		break;
-	case IEEE80211_M_MONITOR:
-		data = htole32(IPW_MODE_MONITOR);
-		break;
-	}
-	DPRINTF(("Setting mode to %u\n", le32toh(data)));
-	error = ipw_cmd(sc, IPW_CMD_SET_MODE, &data, sizeof data);
+	memset(&security, 0, sizeof security);
+	security.authmode = (ni->ni_authmode == IEEE80211_AUTH_SHARED) ?
+	    IPW_AUTH_SHARED : IPW_AUTH_OPEN;
+	security.ciphers = htole32(IPW_CIPHER_NONE);
+	DPRINTF(("Setting authmode to %u\n", security.authmode));
+	error = ipw_cmd(sc, IPW_CMD_SET_SECURITY_INFO, &security,
+	    sizeof security);
 	if (error != 0)
-		return error;
-
-	if (ic->ic_opmode == IEEE80211_M_IBSS ||
-	    ic->ic_opmode == IEEE80211_M_MONITOR) {
-		error = ipw_setchannel(sc, ic->ic_curchan);
-		if (error != 0)
-			return error;
-	}
-
-	if (ic->ic_opmode == IEEE80211_M_MONITOR)
-		return ipw_enable(sc);
-
-	IEEE80211_ADDR_COPY(vap->iv_myaddr, IF_LLADDR(ifp));
-	DPRINTF(("Setting MAC address to %6D\n", vap->iv_myaddr, ":"));
-	error = ipw_cmd(sc, IPW_CMD_SET_MAC_ADDRESS, vap->iv_myaddr,
-	    IEEE80211_ADDR_LEN);
-	if (error != 0)
-		return error;
-
-	config.flags = htole32(IPW_CFG_BSS_MASK | IPW_CFG_IBSS_MASK |
-	    IPW_CFG_PREAMBLE_AUTO | IPW_CFG_802_1x_ENABLE);
-	if (ic->ic_opmode == IEEE80211_M_IBSS)
-		config.flags |= htole32(IPW_CFG_IBSS_AUTO_START);
-	if (ifp->if_flags & IFF_PROMISC)
-		config.flags |= htole32(IPW_CFG_PROMISCUOUS);
-	config.bss_chan = htole32(0x3fff); /* channels 1-14 */
-	config.ibss_chan = htole32(0x7ff); /* channels 1-11 */
-	DPRINTF(("Setting configuration to 0x%x\n", le32toh(config.flags)));
-	error = ipw_cmd(sc, IPW_CMD_SET_CONFIGURATION, &config, sizeof config);
-	if (error != 0)
-		return error;
-
-	data = htole32(0x3); /* 1, 2 */
-	DPRINTF(("Setting basic tx rates to 0x%x\n", le32toh(data)));
-	error = ipw_cmd(sc, IPW_CMD_SET_BASIC_TX_RATES, &data, sizeof data);
-	if (error != 0)
-		return error;
-
-	/* NB: use the same rate set */
-	DPRINTF(("Setting msdu tx rates to 0x%x\n", le32toh(data)));
-	error = ipw_cmd(sc, IPW_CMD_SET_MSDU_TX_RATES, &data, sizeof data);
-	if (error != 0)
-		return error;
-
-	data = htole32(0xf); /* 1, 2, 5.5, 11 */
-	DPRINTF(("Setting tx rates to 0x%x\n", le32toh(data)));
-	error = ipw_cmd(sc, IPW_CMD_SET_TX_RATES, &data, sizeof data);
-	if (error != 0)
-		return error;
-
-	data = htole32(IPW_POWER_MODE_CAM);
-	DPRINTF(("Setting power mode to %u\n", le32toh(data)));
-	error = ipw_cmd(sc, IPW_CMD_SET_POWER_MODE, &data, sizeof data);
-	if (error != 0)
-		return error;
-
-	if (ic->ic_opmode == IEEE80211_M_IBSS) {
-		data = htole32(32); /* default value */
-		DPRINTF(("Setting tx power index to %u\n", le32toh(data)));
-		error = ipw_cmd(sc, IPW_CMD_SET_TX_POWER_INDEX, &data,
-		    sizeof data);
-		if (error != 0)
-			return error;
-	}
+		goto done;
 
 	data = htole32(vap->iv_rtsthreshold);
 	DPRINTF(("Setting RTS threshold to %u\n", le32toh(data)));
 	error = ipw_cmd(sc, IPW_CMD_SET_RTS_THRESHOLD, &data, sizeof data);
 	if (error != 0)
-		return error;
+		goto done;
 
 	data = htole32(vap->iv_fragthreshold);
 	DPRINTF(("Setting frag threshold to %u\n", le32toh(data)));
 	error = ipw_cmd(sc, IPW_CMD_SET_FRAG_THRESHOLD, &data, sizeof data);
 	if (error != 0)
-		return error;
-
-	error = ipw_setssid(sc, vap->iv_des_ssid[0].ssid, vap->iv_des_ssid[0].len);
-	if (error != 0)
-		return error;
-
-	error = ipw_setbssid(sc, NULL);
-	if (error != 0)
-		return error;
-
-	if (vap->iv_flags & IEEE80211_F_DESBSSID) {
-		DPRINTF(("Setting desired BSSID to %6D\n", vap->iv_des_bssid,
-		    ":"));
-		error = ipw_cmd(sc, IPW_CMD_SET_DESIRED_BSSID,
-		    vap->iv_des_bssid, IEEE80211_ADDR_LEN);
-		if (error != 0)
-			return error;
-	}
-
-	memset(&security, 0, sizeof security);
-	security.authmode = (vap->iv_bss->ni_authmode == IEEE80211_AUTH_SHARED) ?
-	    IPW_AUTH_SHARED : IPW_AUTH_OPEN;
-	security.ciphers = htole32(IPW_CIPHER_NONE);
-	DPRINTF(("Setting authmode to %u\n", security.authmode));
-	error = ipw_cmd(sc, IPW_CMD_SET_SECURITY_INFO, &security,
-	    sizeof security);
-	if (error != 0)
-		return error;
+		goto done;
 
 	if (vap->iv_flags & IEEE80211_F_PRIVACY) {
 		error = ipw_setwepkeys(sc);
 		if (error != 0)
-			return error;
+			goto done;
 
 		if (vap->iv_def_txkey != IEEE80211_KEYIX_NONE) {
 			data = htole32(vap->iv_def_txkey);
@@ -2294,7 +2313,7 @@
 			error = ipw_cmd(sc, IPW_CMD_SET_WEP_KEY_INDEX, &data,
 			    sizeof data);
 			if (error != 0)
-				return error;
+				goto done;
 		}
 	}
 
@@ -2302,159 +2321,66 @@
 	DPRINTF(("Setting wep flags to 0x%x\n", le32toh(data)));
 	error = ipw_cmd(sc, IPW_CMD_SET_WEP_FLAGS, &data, sizeof data);
 	if (error != 0)
-		return error;
-
-	if (vap->iv_appie_assocreq != NULL) {
-		struct ieee80211_appie *ie = vap->iv_appie_assocreq;
-		error = ipw_setwpaie(sc, ie->ie_data, ie->ie_len);
-		if (error != 0)
-			return error;
-	}
-
-	if (ic->ic_opmode == IEEE80211_M_IBSS) {
-		data = htole32(ic->ic_bintval);
-		DPRINTF(("Setting beacon interval to %u\n", le32toh(data)));
-		error = ipw_cmd(sc, IPW_CMD_SET_BEACON_INTERVAL, &data,
-		    sizeof data);
-		if (error != 0)
-			return error;
-	}
-
-	error = ipw_setscanopts(sc, 0x3fff, 0);
-	if (error != 0)
-		return error;
-
-	return (ipw_enable(sc));
-}
-
-/*
- * Handler for sc_assoc_task.  This is a simple wrapper around
- * ipw_auth_and_assoc().
- */
-static void
-ipw_assoc_task(void *context, int pending)
-{
-	struct ipw_softc *sc = context;
-	IPW_LOCK_DECL;
-
-	IPW_LOCK(sc);
-	ipw_auth_and_assoc(sc);
-	IPW_UNLOCK(sc);
-}
-
-static int
-ipw_auth_and_assoc(struct ipw_softc *sc)
-{
-	struct ifnet *ifp = sc->sc_ifp;
-	struct ieee80211com *ic = ifp->if_l2com;
-	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
-	struct ieee80211_node *ni = vap->iv_bss;
-	struct ipw_security security;
-	uint32_t data;
-	int error;
-
-	error = ipw_disable(sc);
-	if (error != 0)
-		return (error);
-
-	memset(&security, 0, sizeof security);
-	security.authmode = (ni->ni_authmode == IEEE80211_AUTH_SHARED) ?
-	    IPW_AUTH_SHARED : IPW_AUTH_OPEN;
-	security.ciphers = htole32(IPW_CIPHER_NONE);
-	DPRINTF(("Setting authmode to %u\n", security.authmode));
-	error = ipw_cmd(sc, IPW_CMD_SET_SECURITY_INFO, &security,
-	    sizeof security);
-	if (error != 0)
-		return (error);
-
-	if (vap->iv_flags & IEEE80211_F_PRIVACY) {
-		error = ipw_setwepkeys(sc);
-		if (error != 0)
-			return error;
-
-		if (vap->iv_def_txkey != IEEE80211_KEYIX_NONE) {
-			data = htole32(vap->iv_def_txkey);
-			DPRINTF(("Setting wep tx key index to %u\n",
-				le32toh(data)));
-			error = ipw_cmd(sc, IPW_CMD_SET_WEP_KEY_INDEX, &data,
-			    sizeof data);
-			if (error != 0)
-				return error;
-		}
-	}
+		goto done;
 
-	data = htole32((vap->iv_flags & IEEE80211_F_PRIVACY) ? IPW_WEPON : 0);
-	DPRINTF(("Setting wep flags to 0x%x\n", le32toh(data)));
-	error = ipw_cmd(sc, IPW_CMD_SET_WEP_FLAGS, &data, sizeof data);
-	if (error != 0)
-		return error;
-
 	error = ipw_setssid(sc, ni->ni_essid, ni->ni_esslen);
 	if (error != 0)
-		return (error);
+		goto done;
 
 	error = ipw_setbssid(sc, ni->ni_bssid);
 	if (error != 0)
-		return (error);
+		goto done;
 
 	if (vap->iv_appie_assocreq != NULL) {
 		struct ieee80211_appie *ie = vap->iv_appie_assocreq;
 		error = ipw_setwpaie(sc, ie->ie_data, ie->ie_len);
 		if (error != 0)
-			return error;
+			goto done;
 	}
 	if (ic->ic_opmode == IEEE80211_M_IBSS) {
 		error = ipw_setchannel(sc, ni->ni_chan);
 		if (error != 0)
-			return (error);
+			goto done;
 	}
 
 	/* lock scan to ap's channel and enable associate */
 	error = ipw_setscanopts(sc,
-			1<<(ieee80211_chan2ieee(ic, ni->ni_chan)-1), 0);
+	    1<<(ieee80211_chan2ieee(ic, ni->ni_chan)-1), 0);
+	if (error != 0)
+		goto done;
 
-	return ipw_enable(sc);		/* finally, enable adapter */
+	error = ipw_enable(sc);		/* finally, enable adapter */
+	if (error == 0)
+		sc->flags |= IPW_FLAG_ASSOCIATING;
+done:
+	IPW_UNLOCK(sc);
 }
 
-/*
- * Handler for sc_disassoc_task.  This is a simple wrapper around
- * ipw_disassociate().
- */
 static void
 ipw_disassoc_task(void *context, int pending)
 {
-	struct ipw_softc *sc = context;
+	struct ieee80211vap *vap = context;
+	struct ifnet *ifp = vap->iv_ic->ic_ifp;
+	struct ieee80211_node *ni = vap->iv_bss;
+	struct ipw_softc *sc = ifp->if_softc;
 	IPW_LOCK_DECL;
 
 	IPW_LOCK(sc);
-	ipw_disassociate(sc);
-	IPW_UNLOCK(sc);
-}
-
-static int
-ipw_disassociate(struct ipw_softc *sc)
-{
-	struct ifnet *ifp = sc->sc_ifp;
-	struct ieee80211com *ic = ifp->if_l2com;
-	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
-	struct ieee80211_node *ni = vap->iv_bss;
-
 	DPRINTF(("Disassociate from %6D\n", ni->ni_bssid, ":"));
-
 	/*
 	 * NB: don't try to do this if ipw_stop_master has
 	 *     shutdown the firmware and disabled interrupts.
 	 */
-	if (!(sc->flags & IPW_FLAG_FW_INITED))
-		return (0);
-
-	sc->flags &= ~IPW_FLAG_ASSOCIATED;
-	/*
-	 * NB: firmware currently ignores bssid parameter, but
-	 *     supply it in case this changes (follow linux driver).
-	 */
-	return ipw_cmd(sc, IPW_CMD_DISASSOCIATE,
-		ni->ni_bssid, IEEE80211_ADDR_LEN);
+	if (sc->flags & IPW_FLAG_FW_INITED) {
+		sc->flags &= ~IPW_FLAG_ASSOCIATED;
+		/*
+		 * NB: firmware currently ignores bssid parameter, but
+		 *     supply it in case this changes (follow linux driver).
+		 */
+		(void) ipw_cmd(sc, IPW_CMD_DISASSOCIATE,
+			ni->ni_bssid, IEEE80211_ADDR_LEN);
+	}
+	IPW_UNLOCK(sc);
 }
 
 /*
@@ -2474,20 +2400,19 @@
 	IPW_LOCK_DECL;
 
 	IPW_LOCK(sc);
-	ipw_init_locked(sc, 0);
+	ipw_init_locked(sc);
 	IPW_UNLOCK(sc);
 }
 
 static void
-ipw_init_locked(struct ipw_softc *sc, int force)
+ipw_init_locked(struct ipw_softc *sc)
 {
 	struct ifnet *ifp = sc->sc_ifp;
 	struct ieee80211com *ic = ifp->if_l2com;
 	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
 	const struct firmware *fp;
 	const struct ipw_firmware_hdr *hdr;
-	const char *imagename, *fw;
-	IPW_LOCK_DECL;
+	const char *fw;
 
 	IPW_LOCK_ASSERT(sc);
 
@@ -2507,63 +2432,22 @@
 
 	if (ipw_reset(sc) != 0) {
 		device_printf(sc->sc_dev, "could not reset adapter\n");
-		goto fail1;
-	}
-
-	switch (ic->ic_opmode) {
-	case IEEE80211_M_STA:
-		imagename = "ipw_bss";
-		break;
-	case IEEE80211_M_IBSS:
-		imagename = "ipw_ibss";
-		break;
-	case IEEE80211_M_MONITOR:
-		imagename = "ipw_monitor";
-		break;
-	default:
-		imagename = NULL;	/* should not get there */
-	}
-
-	/*
-	 * Load firmware image using the firmware(9) subsystem.  We need to
-	 * release the driver's lock first.
-	 */
-	if (sc->sc_firmware == NULL || strcmp(sc->sc_firmware->name,
-	    imagename) != 0) {
-		IPW_UNLOCK(sc);
-		if (sc->sc_firmware != NULL)
-			firmware_put(sc->sc_firmware, FIRMWARE_UNLOAD);
-		sc->sc_firmware = firmware_get(imagename);
-		IPW_LOCK(sc);
+		goto fail;
 	}
 
 	if (sc->sc_firmware == NULL) {
-		device_printf(sc->sc_dev,
-		    "could not load firmware image '%s'\n", imagename);
-		goto fail1;
+		device_printf(sc->sc_dev, "no firmware\n");
+		goto fail;
 	}
-
+	/* NB: consistency already checked on load */
 	fp = sc->sc_firmware;
-	if (fp->datasize < sizeof *hdr) {
-		device_printf(sc->sc_dev,
-		    "firmware image too short %zu\n", fp->datasize);
-		goto fail2;
-	}
-
 	hdr = (const struct ipw_firmware_hdr *)fp->data;
 
-	if (fp->datasize < sizeof *hdr + le32toh(hdr->mainsz) +
-	    le32toh(hdr->ucodesz)) {
-		device_printf(sc->sc_dev,
-		    "firmware image too short %zu\n", fp->datasize);
-		goto fail2;
-	}
-
-	DPRINTF(("Loading firmware image '%s'\n", imagename));
+	DPRINTF(("Loading firmware image '%s'\n", fp->name));
 	fw = (const char *)fp->data + sizeof *hdr + le32toh(hdr->mainsz);
 	if (ipw_load_ucode(sc, fw, le32toh(hdr->ucodesz)) != 0) {
 		device_printf(sc->sc_dev, "could not load microcode\n");
-		goto fail2;
+		goto fail;
 	}
 
 	ipw_stop_master(sc);
@@ -2591,7 +2475,7 @@
 	fw = (const char *)fp->data + sizeof *hdr;
 	if (ipw_load_firmware(sc, fw, le32toh(hdr->mainsz)) != 0) {
 		device_printf(sc->sc_dev, "could not load firmware\n");
-		goto fail2;
+		goto fail;
 	}
 
 	sc->flags |= IPW_FLAG_FW_INITED;
@@ -2604,26 +2488,114 @@
 
 	if (ipw_config(sc) != 0) {
 		device_printf(sc->sc_dev, "device configuration failed\n");
-		goto fail1;
+		goto fail;
 	}
 
 	callout_reset(&sc->sc_wdtimer, hz, ipw_watchdog, sc);
 	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;

>>> TRUNCATED FOR MAIL (1000 lines) <<<


More information about the p4-projects mailing list