PERFORCE change 135695 for review

Sam Leffler sam at FreeBSD.org
Tue Feb 19 02:06:44 UTC 2008


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

Change 135695 by sam at sam_ebb on 2008/02/19 02:06:37

	o add multi-vap create
	o add bssid clone/allocation
	o correctly map net80211 opmode to hal mode
	o correct per-vap mcast q reclaim
	o add support for sta mode s/w bmiss when operating as an ap
	o hookup hal calls to check for bssid mask and tsf adjust support

Affected files ...

.. //depot/projects/vap/sys/dev/ath/if_ath.c#24 edit
.. //depot/projects/vap/sys/dev/ath/if_athvar.h#13 edit

Differences ...

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

@@ -579,6 +579,8 @@
 	 */
 	if (ath_hal_hasbursting(ah))
 		ic->ic_caps |= IEEE80211_C_BURST;
+	sc->sc_hasbmask = ath_hal_hasbssidmask(ah);
+	sc->sc_hastsfadd = ath_hal_hastsfadjust(ah);
 	if (ath_hal_hasfastframes(ah))
 		ic->ic_caps |= IEEE80211_C_FF;
 	if (ath_hal_getwirelessmodes(ah, ath_countrycode) & (HAL_MODE_108G|HAL_MODE_TURBO))
@@ -608,7 +610,7 @@
 	ic->ic_max_keyix = sc->sc_keymax;
 	/* call MI attach routine. */
 	ieee80211_ifattach(ic);
-	sc->sc_opmode = ic->ic_opmode;
+	sc->sc_opmode = HAL_M_STA;
 
 	/* override default methods */
 	ic->ic_newassoc = ath_newassoc;
@@ -685,21 +687,117 @@
 	return 0;
 }
 
+/*
+ * MAC address handling for multiple BSS on the same radio.
+ * The first vap uses the MAC address from the EEPROM.  For
+ * subsequent vap's we set the U/L bit (bit 1) in the MAC
+ * address and use the next six bits as an index.
+ */
+static void
+assign_address(struct ath_softc *sc, uint8_t mac[IEEE80211_ADDR_LEN], int clone)
+{
+	int i;
+
+	if (clone && sc->sc_hasbmask) {
+		/* NB: we only do this if h/w supports multiple bssid */
+		for (i = 0; i < 32; i++)
+			if ((sc->sc_bssidmask & (1<<i)) == 0)
+				break;
+		if (i != 0)
+			mac[0] |= (i << 2)|0x2;
+	} else
+		i = 0;
+	sc->sc_bssidmask |= 1<<i;
+	if (i == 0)
+		sc->sc_nbssid0++;
+}
+
+static void
+reclaim_address(struct ath_softc *sc, uint8_t mac[IEEE80211_ADDR_LEN])
+{
+	int i = mac[0] >> 2;
+	if (i != 0 || --sc->sc_nbssid0 == 0)
+		sc->sc_bssidmask &= ~(1<<i);
+}
+
 static struct ieee80211vap *
 ath_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])
+	const uint8_t mac0[IEEE80211_ADDR_LEN])
 {
+	struct ath_softc *sc = ic->ic_ifp->if_softc;
 	struct ath_vap *avp;
 	struct ieee80211vap *vap;
+	uint8_t mac[IEEE80211_ADDR_LEN];
+	int ic_opmode, needbeacon;
 
-	if (!TAILQ_EMPTY(&ic->ic_vaps))		/* only one at a time */
+	needbeacon = 0;
+	IEEE80211_ADDR_COPY(mac, mac0);
+
+	/* XXX ic unlocked and race against add? */
+	switch (opmode) {
+	case IEEE80211_M_STA:
+		if (sc->sc_nstavaps != 0)	/* XXX only 1 sta for now */
+			return NULL;
+		if (sc->sc_nvaps) {
+			/*
+			 * When there are multiple vaps we must fall
+			 * back to s/w beacon miss handling.
+			 */
+			flags |= IEEE80211_CLONE_NOBEACONS;
+		}
+		if (flags & IEEE80211_CLONE_NOBEACONS) {
+			sc->sc_swbmiss = 1;
+			ic_opmode = IEEE80211_M_HOSTAP;
+		} else
+			ic_opmode = opmode;
+		break;
+	case IEEE80211_M_IBSS:
+		if (sc->sc_nvaps != 0)		/* XXX only 1 for now */
+			return NULL;
+		ic_opmode = opmode;
+		needbeacon = 1;
+		break;
+	case IEEE80211_M_AHDEMO:
+		/* fall thru... */
+	case IEEE80211_M_MONITOR:
+		if (sc->sc_nvaps != 0 && ic->ic_opmode != opmode) {
+			/* XXX not right for monitor mode */
+			ic_opmode = ic->ic_opmode;
+		} else
+			ic_opmode = opmode;
+		break;
+	case IEEE80211_M_HOSTAP:
+		needbeacon = 1;
+		/* fall thru... */
+	case IEEE80211_M_WDS:
+		if (sc->sc_nvaps && ic->ic_opmode == IEEE80211_M_STA)
+			return NULL;
+		if (opmode == IEEE80211_M_WDS) {
+			/*
+			 * Silently remove any request for a unique
+			 * bssid; WDS vap's always share the local
+			 * mac address.
+			 */
+			flags &= ~IEEE80211_CLONE_BSSID;
+		}
+		ic_opmode = IEEE80211_M_HOSTAP;
+		break;
+	default:
+		return NULL;
+	}
+	if (needbeacon & STAILQ_EMPTY(&sc->sc_bbuf))
 		return NULL;
+
 	avp = (struct ath_vap *) malloc(sizeof(struct ath_vap),
 	    M_80211_VAP, M_NOWAIT | M_ZERO);
 	if (avp == NULL)
 		return NULL;
+
+	if (opmode == IEEE80211_M_HOSTAP)
+		assign_address(sc, mac, flags & IEEE80211_CLONE_BSSID);
+
 	vap = &avp->av_vap;
 	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
 
@@ -720,10 +818,85 @@
 	avp->av_bmiss = vap->iv_bmiss;
 	vap->iv_bmiss = ath_bmiss_vap;
 
+	avp->av_bslot = -1;
+	if (needbeacon) {
+		/*
+		 * Allocate beacon state and setup the q for buffered
+		 * multicast frames.  We know a beacon buffer is
+		 * available because we checked above.
+		 */
+		avp->av_bcbuf = STAILQ_FIRST(&sc->sc_bbuf);
+		STAILQ_REMOVE_HEAD(&sc->sc_bbuf, bf_list);
+		if (opmode != IEEE80211_M_IBSS || !sc->sc_hasveol) {
+			int slot;
+			/*
+			 * Assign the vap to a beacon xmit slot.  As above
+			 * this cannot fail to find a free one.
+			 */
+			avp->av_bslot = 0;
+			for (slot = 0; slot < ATH_BCBUF; slot++) {
+				if (sc->sc_bslot[slot] == NULL) {
+					/*
+					 * XXX hack, space out slots to better
+					 * deal with traffic coming out of the
+					 * cab q.
+					 */
+					if (slot + 1 < ATH_BCBUF &&
+					    sc->sc_bslot[slot+1] == NULL) {
+						avp->av_bslot = slot + 1;
+						break;
+					} 
+					avp->av_bslot = slot;
+					/* NB: keep looking for a double slot */
+				}
+			}
+			KASSERT(sc->sc_bslot[avp->av_bslot] == NULL,
+			    ("beacon slot %u not empty", avp->av_bslot));
+			sc->sc_bslot[avp->av_bslot] = vap;
+			sc->sc_nbcnvaps++;
+		}
+		if (sc->sc_hastsfadd) {
+			/*
+			 * Multple vaps are to transmit beacons and we
+			 * have h/w support for TSF adjusting; enable
+			 * use of staggered beacons.
+			 */
+			sc->sc_stagbeacons = 1;
+		}
+		STAILQ_INIT(&avp->av_mcastq.axq_q);
+		ATH_TXQ_LOCK_INIT(sc, &avp->av_mcastq);
+	}
 	/* complete setup */
 	ieee80211_vap_attach(vap, ath_media_change, ieee80211_media_status);
 
-	ic->ic_opmode = opmode;
+	ic->ic_opmode = ic_opmode;
+	if (opmode != IEEE80211_M_WDS)
+		sc->sc_nvaps++;
+	switch (ic_opmode) {
+	case IEEE80211_M_IBSS:
+		sc->sc_opmode = HAL_M_IBSS;
+		break;
+	case IEEE80211_M_STA:
+		sc->sc_opmode = HAL_M_STA;
+		break;
+	case IEEE80211_M_AHDEMO:
+	case IEEE80211_M_HOSTAP:
+		sc->sc_opmode = HAL_M_HOSTAP;
+		break;
+	case IEEE80211_M_MONITOR:
+		sc->sc_opmode = HAL_M_MONITOR;
+		break;
+	default:
+		/* XXX should not happen */
+		break;
+	}
+
+	if (sc->sc_hastsfadd) {
+		/*
+		 * Configure whether or not TSF adjust should be done.
+		 */
+		ath_hal_settsfadjust(sc->sc_ah, sc->sc_stagbeacons);
+	}
 	return vap;
 }
 
@@ -746,12 +919,8 @@
 		ath_draintxq(sc);		/* stop xmit side */
 		ath_stoprecv(sc);		/* stop recv side */
 	}
-	/*
-	 * Reclaim any pending mcast frames for the vap.
-	 */
-	ath_tx_draintxq(sc, &avp->av_mcastq);
-	ATH_TXQ_LOCK_DESTROY(&avp->av_mcastq);
 
+	ieee80211_vap_detach(vap);
 	/*
 	 * Reclaim beacon state.  Note this must be done before
 	 * the vap instance is reclaimed as we may have a reference
@@ -766,16 +935,25 @@
 		avp->av_bcbuf = NULL;
 		if (sc->sc_nbcnvaps == 0)
 			sc->sc_stagbeacons = 0;
+		/*
+		 * Reclaim any pending mcast frames for the vap.
+		 */
+		ath_tx_draintxq(sc, &avp->av_mcastq);
+		ATH_TXQ_LOCK_DESTROY(&avp->av_mcastq);
 	}
 	/*
 	 * Update bookkeeping.
 	 */
 	if (vap->iv_opmode == IEEE80211_M_STA) {
 		sc->sc_nstavaps--;
+		if (sc->sc_nstavaps == 0 && sc->sc_swbmiss)
+			sc->sc_swbmiss = 0;
+	} else if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
+		reclaim_address(sc, vap->iv_myaddr);
 	}
-	ieee80211_vap_detach(vap);
+	if (vap->iv_opmode != IEEE80211_M_WDS)
+		sc->sc_nvaps--;
 	free(avp, M_80211_VAP);
-	sc->sc_nvaps--;
 
 	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
 		/*
@@ -2216,13 +2394,17 @@
  *   hostap, adhoc, or monitor modes
  * o enable promiscuous mode according to the interface state
  * o accept beacons:
+ *   - when operating in station mode for collecting rssi data when
+ *     the station is otherwise quiet, or
  *   - when operating in adhoc mode so the 802.11 layer creates
  *     node table entries for peers,
- *   - when operating in station mode for collecting rssi data when
- *     the station is otherwise quiet, or
  *   - when scanning
+ *   - when doing s/w beacon miss (e.g. for ap+sta)
  * o accept control frames:
  *   - when in monitor mode
+ * o accept PHY error frames when hardware doesn't have MIB support
+ *   to count and we need them for ANI (sta mode only at the moment)
+ *   and we are not scanning (ANI is disabled)
  * XXX BAR frames for 11n
  */
 static u_int32_t
@@ -2240,7 +2422,7 @@
 		rfilt |= HAL_RX_FILTER_PROM;
 	if (ic->ic_opmode == IEEE80211_M_STA ||
 	    sc->sc_opmode == HAL_M_IBSS ||
-	    sc->sc_scanning)
+	    sc->sc_swbmiss || sc->sc_scanning)
 		rfilt |= HAL_RX_FILTER_BEACON;
 	if (ic->ic_opmode == IEEE80211_M_MONITOR)
 		rfilt |= HAL_RX_FILTER_CONTROL;
@@ -2977,7 +3159,7 @@
 		nexttbtt = roundup(nexttbtt, intval);
 	DPRINTF(sc, ATH_DEBUG_BEACON, "%s: nexttbtt %u intval %u (%u)\n",
 		__func__, nexttbtt, intval, ni->ni_intval);
-	if (ic->ic_opmode == IEEE80211_M_STA) {
+	if (ic->ic_opmode == IEEE80211_M_STA && !sc->sc_swbmiss) {
 		HAL_BEACON_STATE bs;
 		int dtimperiod, dtimcount;
 		int cfpperiod, cfpcount;

==== //depot/projects/vap/sys/dev/ath/if_athvar.h#13 (text+ko) ====

@@ -206,6 +206,9 @@
 	int			sc_debug;
 	int			sc_nvaps;	/* # vaps */
 	int			sc_nstavaps;	/* # station vaps */
+	u_int8_t		sc_nbssid0;	/* # vap's using base mac */
+	uint32_t		sc_bssidmask;	/* bssid mask */
+
 	u_int32_t		sc_countrycode;
 	u_int32_t		sc_regdomain;
 	void 			(*sc_node_free)(struct ieee80211_node *);
@@ -238,6 +241,7 @@
 				sc_hasbmask : 1,/* bssid mask support */
 				sc_hastsfadd: 1,/* tsf adjust support */
 				sc_beacons  : 1,/* beacons running */
+				sc_swbmiss  : 1,/* sta mode using sw bmiss */
 				sc_stagbeacons:1;/* use staggered beacons */
 						/* rate tables */
 #define	IEEE80211_MODE_HALF	(IEEE80211_MODE_MAX+0)
@@ -552,6 +556,14 @@
 #endif
 #define	ath_hal_hasfastframes(_ah) \
 	(ath_hal_getcapability(_ah, HAL_CAP_FASTFRAME, 0, NULL) == HAL_OK)
+#define	ath_hal_hasbssidmask(_ah) \
+	(ath_hal_getcapability(_ah, HAL_CAP_BSSIDMASK, 0, NULL) == HAL_OK)
+#define	ath_hal_hastsfadjust(_ah) \
+	(ath_hal_getcapability(_ah, HAL_CAP_TSF_ADJUST, 0, NULL) == HAL_OK)
+#define	ath_hal_gettsfadjust(_ah) \
+	(ath_hal_getcapability(_ah, HAL_CAP_TSF_ADJUST, 1, NULL) == HAL_OK)
+#define	ath_hal_settsfadjust(_ah, _onoff) \
+	ath_hal_setcapability(_ah, HAL_CAP_TSF_ADJUST, 1, _onoff, NULL)
 #define	ath_hal_hasrfsilent(_ah) \
 	(ath_hal_getcapability(_ah, HAL_CAP_RFSILENT, 0, NULL) == HAL_OK)
 #define	ath_hal_getrfkill(_ah) \


More information about the p4-projects mailing list