PERFORCE change 135700 for review

Sam Leffler sam at FreeBSD.org
Tue Feb 19 04:57:47 UTC 2008


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

Change 135700 by sam at sam_ebb on 2008/02/19 04:56:47

	Fixups to make multiple ap vaps work:
	o allocate all the beacon buffers (not just 1!)
	o fixup the state machine to to be multi-vap aware
	o move newstate super call up so we have the bss node
	  setup before we do driver work that depends on it
	o import fixups to set associd+bssid in newstate only when needed
	
	While here add printfs to vap_create failure causes; may want to
	move them to debug msgs eventually.

Affected files ...

.. //depot/projects/vap/sys/dev/ath/if_ath.c#25 edit

Differences ...

==== //depot/projects/vap/sys/dev/ath/if_ath.c#25 (text+ko) ====

@@ -738,8 +738,10 @@
 	/* XXX ic unlocked and race against add? */
 	switch (opmode) {
 	case IEEE80211_M_STA:
-		if (sc->sc_nstavaps != 0)	/* XXX only 1 sta for now */
+		if (sc->sc_nstavaps != 0) {	/* XXX only 1 sta for now */
+			device_printf(sc->sc_dev, "only 1 sta vap supported\n");
 			return NULL;
+		}
 		if (sc->sc_nvaps) {
 			/*
 			 * When there are multiple vaps we must fall
@@ -754,8 +756,11 @@
 			ic_opmode = opmode;
 		break;
 	case IEEE80211_M_IBSS:
-		if (sc->sc_nvaps != 0)		/* XXX only 1 for now */
+		if (sc->sc_nvaps != 0) {	/* XXX only 1 for now */
+			device_printf(sc->sc_dev,
+			    "only 1 ibss vap supported\n");
 			return NULL;
+		}
 		ic_opmode = opmode;
 		needbeacon = 1;
 		break;
@@ -772,8 +777,11 @@
 		needbeacon = 1;
 		/* fall thru... */
 	case IEEE80211_M_WDS:
-		if (sc->sc_nvaps && ic->ic_opmode == IEEE80211_M_STA)
+		if (sc->sc_nvaps && ic->ic_opmode == IEEE80211_M_STA) {
+			device_printf(sc->sc_dev,
+			    "wds not supported in sta mode\n");
 			return NULL;
+		}
 		if (opmode == IEEE80211_M_WDS) {
 			/*
 			 * Silently remove any request for a unique
@@ -785,15 +793,20 @@
 		ic_opmode = IEEE80211_M_HOSTAP;
 		break;
 	default:
+		device_printf(sc->sc_dev, "unknown opmode %d\n", opmode);
 		return NULL;
 	}
-	if (needbeacon & STAILQ_EMPTY(&sc->sc_bbuf))
+	if (needbeacon & STAILQ_EMPTY(&sc->sc_bbuf)) {
+		device_printf(sc->sc_dev, "no beacon buffer available\n");
 		return NULL;
+	}
 
 	avp = (struct ath_vap *) malloc(sizeof(struct ath_vap),
 	    M_80211_VAP, M_NOWAIT | M_ZERO);
-	if (avp == NULL)
+	if (avp == NULL) {
+		device_printf(sc->sc_dev, "unable to allocate memory\n");
 		return NULL;
+	}
 
 	if (opmode == IEEE80211_M_HOSTAP)
 		assign_address(sc, mac, flags & IEEE80211_CLONE_BSSID);
@@ -3475,7 +3488,7 @@
 	}
 
 	error = ath_descdma_setup(sc, &sc->sc_bdma, &sc->sc_bbuf,
-			"beacon", 1, 1);
+			"beacon", ATH_BCBUF, 1);
 	if (error != 0) {
 		ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf);
 		ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf);
@@ -5397,6 +5410,22 @@
 		sc->sc_syncbeacon = 1;
 }
 
+/* 
+ * Walk the vap list and check if there any vap's in RUN state.
+ */
+static int
+ath_isanyrunningvaps(const struct ieee80211vap *this)
+{
+	const struct ieee80211com *ic = this->iv_ic;
+	const struct ieee80211vap *vap;
+
+	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
+		if (vap != this && vap->iv_state == IEEE80211_S_RUN)
+			return 1;
+	}
+	return 0;
+}
+
 static int
 ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
 {
@@ -5404,8 +5433,8 @@
 	struct ath_softc *sc = ic->ic_ifp->if_softc;
 	struct ath_vap *avp = ATH_VAP(vap);
 	struct ath_hal *ah = sc->sc_ah;
-	struct ieee80211_node *ni;
-	int i, error, stamode;
+	struct ieee80211_node *ni = NULL;
+	int i, error;
 	u_int32_t rfilt;
 	static const HAL_LED_STATE leds[] = {
 	    HAL_LED_INIT,	/* IEEE80211_S_INIT */
@@ -5427,40 +5456,41 @@
 
 	if (nstate == IEEE80211_S_INIT) {
 		/*
-		 * Shutdown host/driver operation:
+		 * If there are no vaps left in RUN state then
+		 * shutdown host/driver operation:
 		 * o disable interrupts so we don't rx frames
 		 * o clean any pending items on the task q
 		 * o notify the rate control algorithm
 		 */
-		sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS);
-		ath_hal_intrset(ah, sc->sc_imask &~ HAL_INT_GLOBAL);
+		if (!ath_isanyrunningvaps(vap)) {
+			sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS);
+			/*
+			 * Disable interrupts.
+			 */
+			ath_hal_intrset(ah, sc->sc_imask &~ HAL_INT_GLOBAL);
+			sc->sc_beacons = 0;
 #if 0
-		/* XXX can't use taskqueue_drain 'cuz we're holding sc_mtx */
-		taskqueue_drain(sc->sc_tq, &sc->sc_rxtask);
-		taskqueue_drain(sc->sc_tq, &sc->sc_rxorntask);
-		taskqueue_drain(sc->sc_tq, &sc->sc_bmisstask);
-		taskqueue_drain(sc->sc_tq, &sc->sc_bstucktask);
+			/* XXX can't use taskqueue_drain 'cuz we're holding sc_mtx */
+			taskqueue_drain(sc->sc_tq, &sc->sc_rxtask);
+			taskqueue_drain(sc->sc_tq, &sc->sc_rxorntask);
+			taskqueue_drain(sc->sc_tq, &sc->sc_bmisstask);
+			taskqueue_drain(sc->sc_tq, &sc->sc_bstucktask);
 #endif
+		}
 		ath_rate_newstate(vap, nstate);
-		goto done;
+		return avp->av_newstate(vap, nstate, arg);
 	}
+
 	ni = vap->iv_bss;
-
 	rfilt = ath_calcrxfilter(sc);
-	stamode = (sc->sc_opmode == HAL_M_STA || sc->sc_opmode == HAL_M_IBSS);
-	if (stamode && nstate == IEEE80211_S_RUN) {
+	if (vap->iv_opmode == IEEE80211_M_STA && nstate == IEEE80211_S_RUN) {
 		sc->sc_curaid = ni->ni_associd;
 		IEEE80211_ADDR_COPY(sc->sc_curbssid, ni->ni_bssid);
-	} else
-		sc->sc_curaid = 0;
-
+		ath_hal_setassocid(ah, sc->sc_curbssid, sc->sc_curaid);
+	}
 	DPRINTF(sc, ATH_DEBUG_STATE, "%s: RX filter 0x%x bssid %s aid 0x%x\n",
-		 __func__, rfilt, ether_sprintf(sc->sc_curbssid),
-		 sc->sc_curaid);
-
+	   __func__, rfilt, ether_sprintf(sc->sc_curbssid), sc->sc_curaid);
 	ath_hal_setrxfilter(ah, rfilt);
-	if (stamode)
-		ath_hal_setassocid(ah, sc->sc_curbssid, ni->ni_associd);
 
 	if (vap->iv_opmode != IEEE80211_M_STA &&
 	    (vap->iv_flags & IEEE80211_F_PRIVACY)) {
@@ -5468,23 +5498,26 @@
 			if (ath_hal_keyisvalid(ah, i))
 				ath_hal_keysetmac(ah, i, ni->ni_bssid);
 	}
-
 	/*
 	 * Notify the rate control algorithm so rates
 	 * are setup should ath_beacon_alloc be called.
 	 */
 	ath_rate_newstate(vap, nstate);
 
-	if (nstate == IEEE80211_S_RUN) {
+	/*
+	 * Invoke the parent method to do net80211 work.
+	 */
+	error = avp->av_newstate(vap, nstate, arg);
+
+	if (error == 0 && nstate == IEEE80211_S_RUN) {
+		/* NB: collect bss node again, it may have changed */
+		ni = vap->iv_bss;
+
 		DPRINTF(sc, ATH_DEBUG_STATE,
-			"%s(RUN): iv_flags=0x%08x iv=%d bssid=%s "
-			"capinfo=0x%04x chan=%d\n"
-			 , __func__
-			 , vap->iv_flags
-			 , ni->ni_intval
-			 , ether_sprintf(ni->ni_bssid)
-			 , ni->ni_capinfo
-			 , ieee80211_chan2ieee(ic, ic->ic_curchan));
+		    "%s(RUN): iv_flags 0x%08x bintvl %d bssid %s "
+		    "capinfo 0x%04x chan %d\n", __func__,
+		    vap->iv_flags, ni->ni_intval, ether_sprintf(ni->ni_bssid),
+		    ni->ni_capinfo, ieee80211_chan2ieee(ic, ic->ic_curchan));
 
 		switch (vap->iv_opmode) {
 		case IEEE80211_M_HOSTAP:
@@ -5499,7 +5532,7 @@
 			 * be called with beacon transmission active.
 			 */
 			ath_hal_stoptxdma(ah, sc->sc_bhalq);
-			ath_beacon_free(sc);
+
 			error = ath_beacon_alloc(sc, ni);
 			if (error != 0)
 				goto bad;
@@ -5507,13 +5540,17 @@
 			 * If joining an adhoc network defer beacon timer
 			 * configuration to the next beacon frame so we
 			 * have a current TSF to use.  Otherwise we're
-			 * starting an ibss/bss so there's no need to delay.
+			 * starting an ibss/bss so there's no need to delay;
+			 * if this is the first vap moving to RUN state, then
+			 * beacon state needs to be [re]configured.
 			 */
 			if (vap->iv_opmode == IEEE80211_M_IBSS &&
-			    vap->iv_bss->ni_tstamp.tsf != 0)
+			    ni->ni_tstamp.tsf != 0) {
 				sc->sc_syncbeacon = 1;
-			else
+			} else if (!sc->sc_beacons) {
 				ath_beacon_config(sc, vap);
+				sc->sc_beacons = 1;
+			}
 			break;
 		case IEEE80211_M_STA:
 			/*
@@ -5530,6 +5567,8 @@
 			 */
 			sc->sc_syncbeacon = 1;
 			break;
+		case IEEE80211_M_WDS:
+			break;
 		default:
 			break;
 		}
@@ -5544,24 +5583,19 @@
 		sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
 		sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER;
 		sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER;
+		/*
+		 * Finally, start any timers.
+		 */
+		if (sc->sc_calinterval != 0) {
+			/* start periodic recalibration timer */
+			callout_reset(&sc->sc_cal_ch, sc->sc_calinterval * hz,
+				ath_calibrate, sc);
+		}
 	} else {
 		ath_hal_intrset(ah,
 		    sc->sc_imask &~ (HAL_INT_SWBA | HAL_INT_BMISS));
 		sc->sc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS);
 	}
-done:
-	/*
-	 * Invoke the parent method to complete the work.
-	 */
-	error = avp->av_newstate(vap, nstate, arg);
-	/*
-	 * Finally, start any timers.
-	 */
-	if (nstate == IEEE80211_S_RUN) {
-		/* start periodic recalibration timer */
-		callout_reset(&sc->sc_cal_ch, sc->sc_calinterval * hz,
-			ath_calibrate, sc);
-	}
 bad:
 	return error;
 }


More information about the p4-projects mailing list