PERFORCE change 135687 for review

Sam Leffler sam at FreeBSD.org
Tue Feb 19 00:12:41 UTC 2008


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

Change 135687 by sam at sam_ebb on 2008/02/19 00:12:15

	first step towards vap support

Affected files ...

.. //depot/projects/vap/sys/dev/ath/ath_rate/sample/sample.c#7 edit
.. //depot/projects/vap/sys/dev/ath/ath_rate/sample/sample.h#5 edit
.. //depot/projects/vap/sys/dev/ath/if_ath.c#22 edit
.. //depot/projects/vap/sys/dev/ath/if_athrate.h#7 edit
.. //depot/projects/vap/sys/dev/ath/if_athvar.h#12 edit

Differences ...

==== //depot/projects/vap/sys/dev/ath/ath_rate/sample/sample.c#7 (text+ko) ====

@@ -671,15 +671,15 @@
 ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni)
 {
 #define	RATE(_ix)	(ni->ni_rates.rs_rates[(_ix)] & IEEE80211_RATE_VAL)
-	struct ieee80211com *ic = &sc->sc_ic;
 	struct ath_node *an = ATH_NODE(ni);
+	const struct ieee80211_txparam *tp = an->an_tp;
 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
 	const HAL_RATE_TABLE *rt = sc->sc_currates;
 	int x, y, srate;
 
 	KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
         sn->static_rate_ndx = -1;
-	if (ic->ic_fixed_rate != IEEE80211_FIXED_RATE_NONE) {
+	if (tp != NULL && tp->ucastrate != IEEE80211_FIXED_RATE_NONE) {
 		/*
 		 * A fixed rate is to be used; ic_fixed_rate is the
 		 * IEEE code for this rate (sans basic bit).  Convert this
@@ -688,7 +688,7 @@
 		 */
 		/* NB: the rate set is assumed sorted */
 		srate = ni->ni_rates.rs_nrates - 1;
-		for (; srate >= 0 && RATE(srate) != ic->ic_fixed_rate; srate--)
+		for (; srate >= 0 && RATE(srate) != tp->ucastrate; srate--)
 			;
 		/*
 		 * The fixed rate may not be available due to races
@@ -786,18 +786,19 @@
  * Reset the rate control state for each 802.11 state transition.
  */
 void
-ath_rate_newstate(struct ath_softc *sc, enum ieee80211_state state)
+ath_rate_newstate(struct ieee80211vap *vap, enum ieee80211_state state)
 {
-	struct ieee80211com *ic = &sc->sc_ic;
+	struct ieee80211com *ic = vap->iv_ic;
+	struct ath_softc *sc = ic->ic_ifp->if_softc;
 
 	if (state == IEEE80211_S_RUN) {
-		if (ic->ic_opmode != IEEE80211_M_STA) {
+		if (vap->iv_opmode != IEEE80211_M_STA) {
 			/*
 			 * Sync rates for associated stations and neighbors.
 			 */
 			ieee80211_iterate_nodes(&ic->ic_sta, rate_cb, sc);
 		}
-		ath_rate_newassoc(sc, ATH_NODE(ic->ic_bss), 1);
+		ath_rate_newassoc(sc, ATH_NODE(vap->iv_bss), 1);
 	}
 }
 

==== //depot/projects/vap/sys/dev/ath/ath_rate/sample/sample.h#5 (text+ko) ====


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

@@ -99,49 +99,57 @@
 	ATH_LED_POLL,
 };
 
+static struct ieee80211vap *ath_vap_create(struct ieee80211com *,
+		    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	ath_vap_delete(struct ieee80211vap *);
 static void	ath_init(void *);
 static void	ath_stop_locked(struct ifnet *);
 static void	ath_stop(struct ifnet *);
 static void	ath_start(struct ifnet *);
 static int	ath_reset(struct ifnet *);
+static int	ath_reset_vap(struct ieee80211vap *);
 static int	ath_media_change(struct ifnet *);
 static void	ath_watchdog(struct ifnet *);
 static int	ath_ioctl(struct ifnet *, u_long, caddr_t);
 static void	ath_fatal_proc(void *, int);
 static void	ath_rxorn_proc(void *, int);
+static void	ath_bmiss_vap(struct ieee80211vap *);
 static void	ath_bmiss_proc(void *, int);
-static int	ath_key_alloc(struct ieee80211com *,
+static int	ath_key_alloc(struct ieee80211vap *,
 			const struct ieee80211_key *,
 			ieee80211_keyix *, ieee80211_keyix *);
-static int	ath_key_delete(struct ieee80211com *,
+static int	ath_key_delete(struct ieee80211vap *,
 			const struct ieee80211_key *);
-static int	ath_key_set(struct ieee80211com *, const struct ieee80211_key *,
+static int	ath_key_set(struct ieee80211vap *, const struct ieee80211_key *,
 			const u_int8_t mac[IEEE80211_ADDR_LEN]);
-static void	ath_key_update_begin(struct ieee80211com *);
-static void	ath_key_update_end(struct ieee80211com *);
+static void	ath_key_update_begin(struct ieee80211vap *);
+static void	ath_key_update_end(struct ieee80211vap *);
 static void	ath_mode_init(struct ath_softc *);
 static void	ath_setslottime(struct ath_softc *);
 static void	ath_updateslot(struct ifnet *);
 static int	ath_beaconq_setup(struct ath_hal *);
 static int	ath_beacon_alloc(struct ath_softc *, struct ieee80211_node *);
-static void	ath_beacon_update(struct ieee80211com *, int item);
+static void	ath_beacon_update(struct ieee80211vap *, int item);
 static void	ath_beacon_setup(struct ath_softc *, struct ath_buf *);
 static void	ath_beacon_proc(void *, int);
+static struct ath_buf *ath_beacon_generate(struct ath_softc *,
+			struct ieee80211vap *);
 static void	ath_bstuck_proc(void *, int);
+static void	ath_beacon_return(struct ath_softc *, struct ath_buf *);
 static void	ath_beacon_free(struct ath_softc *);
-static void	ath_beacon_config(struct ath_softc *);
+static void	ath_beacon_config(struct ath_softc *, struct ieee80211vap *);
 static void	ath_descdma_cleanup(struct ath_softc *sc,
 			struct ath_descdma *, ath_bufhead *);
 static int	ath_desc_alloc(struct ath_softc *);
 static void	ath_desc_free(struct ath_softc *);
 static struct ieee80211_node *ath_node_alloc(struct ieee80211_node_table *);
 static void	ath_node_free(struct ieee80211_node *);
-static int8_t	ath_node_getrssi(const struct ieee80211_node *);
 static void	ath_node_getsignal(const struct ieee80211_node *,
 			int8_t *, int8_t *);
 static int	ath_rxbuf_init(struct ath_softc *, struct ath_buf *);
-static void	ath_recv_mgmt(struct ieee80211com *ic, struct mbuf *m,
-			struct ieee80211_node *ni,
+static void	ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
 			int subtype, int rssi, int noise, u_int32_t rstamp);
 static void	ath_setdefantenna(struct ath_softc *, u_int);
 static void	ath_rx_proc(void *, int);
@@ -157,6 +165,7 @@
 static void	ath_tx_proc_q0(void *, int);
 static void	ath_tx_proc_q0123(void *, int);
 static void	ath_tx_proc(void *, int);
+static void	ath_tx_draintxq(struct ath_softc *, struct ath_txq *);
 static int	ath_chan_set(struct ath_softc *, struct ieee80211_channel *);
 static void	ath_draintxq(struct ath_softc *);
 static void	ath_stoprecv(struct ath_softc *);
@@ -166,13 +175,12 @@
 static void	ath_scan_end(struct ieee80211com *);
 static void	ath_set_channel(struct ieee80211com *);
 static void	ath_calibrate(void *);
-static int	ath_newstate(struct ieee80211com *, enum ieee80211_state, int);
+static int	ath_newstate(struct ieee80211vap *, enum ieee80211_state, int);
 static void	ath_setup_stationkey(struct ieee80211_node *);
 static void	ath_newassoc(struct ieee80211_node *, int);
 static int	ath_getchannels(struct ath_softc *,
 			HAL_REG_DOMAIN, HAL_CTRY_CODE, HAL_BOOL, HAL_BOOL);
 static void	ath_led_event(struct ath_softc *, int);
-static void	ath_update_txpow(struct ath_softc *);
 
 static int	ath_rate_setup(struct ath_softc *, u_int mode);
 static void	ath_setcurmode(struct ath_softc *, enum ieee80211_phymode);
@@ -378,7 +386,6 @@
 		goto bad;
 	}
 	callout_init(&sc->sc_cal_ch, CALLOUT_MPSAFE);
-	callout_init(&sc->sc_dfs_ch, CALLOUT_MPSAFE);
 
 	ATH_TXBUF_LOCK_INIT(sc);
 
@@ -412,8 +419,6 @@
 		error = EIO;
 		goto bad2;
 	}
-	/* NB: s/w q, qnum used only by WITNESS */
-	ath_txq_init(sc, &sc->sc_mcastq, HAL_NUM_TX_QUEUES+1);
 	/* NB: insure BK queue is the lowest priority h/w queue */
 	if (!ath_tx_setup(sc, WME_AC_BK, HAL_WME_AC_BK)) {
 		if_printf(ifp, "unable to setup xmit queue for %s traffic!\n",
@@ -497,10 +502,6 @@
 	IFQ_SET_READY(&ifp->if_snd);
 
 	ic->ic_ifp = ifp;
-	ic->ic_reset = ath_reset;
-	ic->ic_newassoc = ath_newassoc;
-	ic->ic_updateslot = ath_updateslot;
-	ic->ic_wme.wme_update = ath_wme_update;
 	/* XXX not right but it's not used anywhere important */
 	ic->ic_phytype = IEEE80211_T_OFDM;
 	ic->ic_opmode = IEEE80211_M_STA;
@@ -603,32 +604,26 @@
 	/* get mac address from hardware */
 	ath_hal_getmac(ah, ic->ic_myaddr);
 
+	/* NB: used to size node table key mapping array */
+	ic->ic_max_keyix = sc->sc_keymax;
 	/* call MI attach routine. */
 	ieee80211_ifattach(ic);
 	sc->sc_opmode = ic->ic_opmode;
+
 	/* override default methods */
+	ic->ic_newassoc = ath_newassoc;
+	ic->ic_updateslot = ath_updateslot;
+	ic->ic_wme.wme_update = ath_wme_update;
+	ic->ic_vap_create = ath_vap_create;
+	ic->ic_vap_delete = ath_vap_delete;
+	ic->ic_raw_xmit = ath_raw_xmit;
 	ic->ic_node_alloc = ath_node_alloc;
 	sc->sc_node_free = ic->ic_node_free;
 	ic->ic_node_free = ath_node_free;
-	ic->ic_node_getrssi = ath_node_getrssi;
 	ic->ic_node_getsignal = ath_node_getsignal;
-	sc->sc_recv_mgmt = ic->ic_recv_mgmt;
-	ic->ic_recv_mgmt = ath_recv_mgmt;
-	sc->sc_newstate = ic->ic_newstate;
-	ic->ic_newstate = ath_newstate;
 	ic->ic_scan_start = ath_scan_start;
 	ic->ic_scan_end = ath_scan_end;
 	ic->ic_set_channel = ath_set_channel;
-	ic->ic_crypto.cs_max_keyix = sc->sc_keymax;
-	ic->ic_crypto.cs_key_alloc = ath_key_alloc;
-	ic->ic_crypto.cs_key_delete = ath_key_delete;
-	ic->ic_crypto.cs_key_set = ath_key_set;
-	ic->ic_crypto.cs_key_update_begin = ath_key_update_begin;
-	ic->ic_crypto.cs_key_update_end = ath_key_update_end;
-	ic->ic_raw_xmit = ath_raw_xmit;
-	ic->ic_update_beacon = ath_beacon_update;
-	/* complete initialization */
-	ieee80211_media_init(ic, ath_media_change, ieee80211_media_status);
 
 	ath_bpfattach(sc);
 	/*
@@ -690,6 +685,112 @@
 	return 0;
 }
 
+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])
+{
+	struct ath_vap *avp;
+	struct ieee80211vap *vap;
+
+	if (!TAILQ_EMPTY(&ic->ic_vaps))		/* only one at a time */
+		return NULL;
+	avp = (struct ath_vap *) malloc(sizeof(struct ath_vap),
+	    M_80211_VAP, M_NOWAIT | M_ZERO);
+	if (avp == NULL)
+		return NULL;
+	vap = &avp->av_vap;
+	ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
+
+	/* h/w crypto support */
+	vap->iv_key_alloc = ath_key_alloc;
+	vap->iv_key_delete = ath_key_delete;
+	vap->iv_key_set = ath_key_set;
+	vap->iv_key_update_begin = ath_key_update_begin;
+	vap->iv_key_update_end = ath_key_update_end;
+
+	/* override various methods */
+	avp->av_recv_mgmt = vap->iv_recv_mgmt;
+	vap->iv_recv_mgmt = ath_recv_mgmt;
+	vap->iv_reset = ath_reset_vap;
+	vap->iv_update_beacon = ath_beacon_update;
+	avp->av_newstate = vap->iv_newstate;
+	vap->iv_newstate = ath_newstate;
+	avp->av_bmiss = vap->iv_bmiss;
+	vap->iv_bmiss = ath_bmiss_vap;
+
+	/* complete setup */
+	ieee80211_vap_attach(vap, ath_media_change, ieee80211_media_status);
+
+	ic->ic_opmode = opmode;
+	return vap;
+}
+
+static void
+ath_vap_delete(struct ieee80211vap *vap)
+{
+	struct ieee80211com *ic = vap->iv_ic;
+	struct ifnet *ifp = ic->ic_ifp;
+	struct ath_softc *sc = ifp->if_softc;
+	struct ath_hal *ah = sc->sc_ah;
+	struct ath_vap *avp = ATH_VAP(vap);
+
+	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+		/*
+		 * Quiesce the hardware while we remove the vap.  In
+		 * particular we need to reclaim all references to
+		 * the vap state by any frames pending on the tx queues.
+		 */
+		ath_hal_intrset(ah, 0);		/* disable interrupts */
+		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);
+
+	/*
+	 * Reclaim beacon state.  Note this must be done before
+	 * the vap instance is reclaimed as we may have a reference
+	 * to it in the buffer for the beacon frame.
+	 */
+	if (avp->av_bcbuf != NULL) {
+		if (avp->av_bslot != -1) {
+			sc->sc_bslot[avp->av_bslot] = NULL;
+			sc->sc_nbcnvaps--;
+		}
+		ath_beacon_return(sc, avp->av_bcbuf);
+		avp->av_bcbuf = NULL;
+		if (sc->sc_nbcnvaps == 0)
+			sc->sc_stagbeacons = 0;
+	}
+	/*
+	 * Update bookkeeping.
+	 */
+	if (vap->iv_opmode == IEEE80211_M_STA) {
+		sc->sc_nstavaps--;
+	}
+	ieee80211_vap_detach(vap);
+	free(avp, M_80211_VAP);
+	sc->sc_nvaps--;
+
+	if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+		/*
+		 * Restart rx+tx machines if still running (RUNNING will
+		 * be reset if we just destroyed the last vap).
+		 */
+		if (ath_startrecv(sc) != 0)
+			if_printf(ifp, "%s: unable to restart recv logic\n",
+			    __func__);
+		if (sc->sc_beacons)
+			ath_beacon_config(sc, NULL);
+		ath_hal_intrset(ah, sc->sc_imask);
+	}
+}
+
 void
 ath_suspend(struct ath_softc *sc)
 {
@@ -864,37 +965,39 @@
 }
 
 static void
+ath_bmiss_vap(struct ieee80211vap *vap)
+{
+	struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
+	u_int64_t lastrx = sc->sc_lastrx;
+	u_int64_t tsf = ath_hal_gettsf64(sc->sc_ah);
+	u_int bmisstimeout =
+		vap->iv_bmissthreshold * vap->iv_bss->ni_intval * 1024;
+
+	DPRINTF(sc, ATH_DEBUG_BEACON,
+	    "%s: tsf %llu lastrx %lld (%llu) bmiss %u\n",
+	    __func__, (unsigned long long) tsf,
+	    (unsigned long long)(tsf - lastrx),
+	    (unsigned long long) lastrx, bmisstimeout);
+	/*
+	 * Workaround phantom bmiss interrupts by sanity-checking
+	 * the time of our last rx'd frame.  If it is within the
+	 * beacon miss interval then ignore the interrupt.  If it's
+	 * truly a bmiss we'll get another interrupt soon and that'll
+	 * be dispatched up for processing.
+	 */
+	if (tsf - lastrx > bmisstimeout)
+		ATH_VAP(vap)->av_bmiss(vap);
+	else
+		sc->sc_stats.ast_bmiss_phantom++;
+}
+
+static void
 ath_bmiss_proc(void *arg, int pending)
 {
 	struct ath_softc *sc = arg;
-	struct ieee80211com *ic = &sc->sc_ic;
 
 	DPRINTF(sc, ATH_DEBUG_ANY, "%s: pending %u\n", __func__, pending);
-	KASSERT(ic->ic_opmode == IEEE80211_M_STA,
-		("unexpect operating mode %u", ic->ic_opmode));
-	if (ic->ic_state == IEEE80211_S_RUN) {
-		u_int64_t lastrx = sc->sc_lastrx;
-		u_int64_t tsf = ath_hal_gettsf64(sc->sc_ah);
-		u_int bmisstimeout =
-			ic->ic_bmissthreshold * ic->ic_bss->ni_intval * 1024;
-
-		DPRINTF(sc, ATH_DEBUG_BEACON,
-		    "%s: tsf %llu lastrx %lld (%llu) bmiss %u\n",
-		    __func__, (unsigned long long) tsf,
-		    (unsigned long long)(tsf - lastrx),
-		    (unsigned long long) lastrx, bmisstimeout);
-		/*
-		 * Workaround phantom bmiss interrupts by sanity-checking
-		 * the time of our last rx'd frame.  If it is within the
-		 * beacon miss interval then ignore the interrupt.  If it's
-		 * truly a bmiss we'll get another interrupt soon and that'll
-		 * be dispatched up for processing.
-		 */
-		if (tsf - lastrx > bmisstimeout)
-			ieee80211_beacon_miss(ic);
-		else
-			sc->sc_stats.ast_bmiss_phantom++;
-	}
+	ieee80211_beacon_miss(&sc->sc_ic);
 }
 
 /*
@@ -971,13 +1074,9 @@
 			status);
 		goto done;
 	}
+	ath_chan_change(sc, ic->ic_curchan);
 
 	/*
-	 * This is needed only to setup initial state
-	 * but it's best done after a reset.
-	 */
-	ath_update_txpow(sc);
-	/*
 	 * Likewise this is set during reset so update
 	 * state cached in the driver.
 	 */
@@ -1009,27 +1108,16 @@
 	 */
 	if (sc->sc_needmib && ic->ic_opmode == IEEE80211_M_STA)
 		sc->sc_imask |= HAL_INT_MIB;
-	ath_hal_intrset(ah, sc->sc_imask);
 
 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
-	ic->ic_state = IEEE80211_S_INIT;
+	ath_hal_intrset(ah, sc->sc_imask);
 
-	/*
-	 * The hardware should be ready to go now so it's safe
-	 * to kick the 802.11 state machine as it's likely to
-	 * immediately call back to us to send mgmt frames.
-	 */
-	ath_chan_change(sc, ic->ic_curchan);
 #ifdef ATH_TX99_DIAG
 	if (sc->sc_tx99 != NULL)
 		sc->sc_tx99->start(sc->sc_tx99);
 	else
 #endif
-	if (ic->ic_opmode != IEEE80211_M_MONITOR) {
-		if (ic->ic_roaming != IEEE80211_ROAMING_MANUAL)
-			ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
-	} else
-		ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
+	ieee80211_start_all(ic);		/* start all vap's */
 done:
 	ATH_UNLOCK(sc);
 }
@@ -1038,7 +1126,6 @@
 ath_stop_locked(struct ifnet *ifp)
 {
 	struct ath_softc *sc = ifp->if_softc;
-	struct ieee80211com *ic = &sc->sc_ic;
 	struct ath_hal *ah = sc->sc_ah;
 
 	DPRINTF(sc, ATH_DEBUG_ANY, "%s: invalid %u if_flags 0x%x\n",
@@ -1065,7 +1152,6 @@
 		if (sc->sc_tx99 != NULL)
 			sc->sc_tx99->stop(sc->sc_tx99);
 #endif
-		ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
 		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
 		ifp->if_timer = 0;
 		if (!sc->sc_invalid) {
@@ -1083,8 +1169,7 @@
 			ath_hal_phydisable(ah);
 		} else
 			sc->sc_rxlink = NULL;
-		IFQ_DRV_PURGE(&ifp->if_snd);
-		ath_beacon_free(sc);
+		ath_beacon_free(sc);	/* XXX not needed */
 	}
 }
 
@@ -1138,7 +1223,6 @@
 	if (!ath_hal_reset(ah, sc->sc_opmode, &sc->sc_curchan, AH_TRUE, &status))
 		if_printf(ifp, "%s: unable to reset hardware; hal status %u\n",
 			__func__, status);
-	ath_update_txpow(sc);		/* update tx power state */
 	sc->sc_diversity = ath_hal_getdiversity(ah);
 	sc->sc_calinterval = 1;
 	sc->sc_caltries = 0;
@@ -1150,14 +1234,20 @@
 	 * might change as a result.
 	 */
 	ath_chan_change(sc, ic->ic_curchan);
-	if (ic->ic_state == IEEE80211_S_RUN)
-		ath_beacon_config(sc);	/* restart beacons */
+	if (sc->sc_beacons)
+		ath_beacon_config(sc, NULL);	/* restart beacons */
 	ath_hal_intrset(ah, sc->sc_imask);
 
 	ath_start(ifp);			/* restart xmit */
 	return 0;
 }
 
+static int
+ath_reset_vap(struct ieee80211vap *vap)
+{
+	return ath_reset(vap->iv_ic->ic_ifp);
+}
+
 static int 
 ath_ff_always(struct ath_txq *txq, struct ath_buf *bf)
 {
@@ -1210,7 +1300,7 @@
 		sc->sc_stats.ast_ff_flush++;
 		
 		/* encap and xmit */
-		bf->bf_m = ieee80211_encap(&sc->sc_ic, bf->bf_m, ni);
+		bf->bf_m = ieee80211_encap(ni, bf->bf_m);
 		if (bf->bf_m == NULL) {
 			DPRINTF(sc, ATH_DEBUG_XMIT | ATH_DEBUG_FF,
 				"%s: discard, encapsulation failure\n",
@@ -1330,7 +1420,6 @@
 ath_ff_check(struct ath_softc *sc, struct ath_txq *txq,
 	struct ath_buf *bf, struct mbuf *m, struct ieee80211_node *ni)
 {
-	struct ieee80211com *ic = ni->ni_ic;
 	struct ath_node *an = ATH_NODE(ni);
 	struct ath_buf *bfstaged;
 	int ff_flush, pri;
@@ -1423,7 +1512,7 @@
 			ether_sprintf(an->an_node.ni_macaddr));
 
 		/* encap and xmit */
-		bfstaged->bf_m = ieee80211_encap(ic, bfstaged->bf_m, ni);
+		bfstaged->bf_m = ieee80211_encap(ni, bfstaged->bf_m);
 		if (bfstaged->bf_m == NULL) {
 			DPRINTF(sc, ATH_DEBUG_XMIT | ATH_DEBUG_FF,
 				"%s: discard, encap failure\n", __func__);
@@ -1525,13 +1614,10 @@
 ath_start(struct ifnet *ifp)
 {
 	struct ath_softc *sc = ifp->if_softc;
-	struct ath_hal *ah = sc->sc_ah;
 	struct ieee80211com *ic = &sc->sc_ic;
 	struct ieee80211_node *ni;
 	struct ath_buf *bf;
 	struct mbuf *m, *next;
-	struct ieee80211_frame *wh;
-	struct ether_header *eh;
 	struct ath_txq *txq;
 	ath_bufhead frags;
 	int pri;
@@ -1539,6 +1625,9 @@
 	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid)
 		return;
 	for (;;) {
+		IFQ_POLL(&ifp->if_snd, m);
+		if (m == NULL)
+			break;
 		/*
 		 * Grab a TX buffer and associated resources.
 		 */
@@ -1550,158 +1639,70 @@
 		if (bf == NULL) {
 			DPRINTF(sc, ATH_DEBUG_XMIT, "%s: out of xmit buffers\n",
 				__func__);
+			/* XXX tail drop */
 			sc->sc_stats.ast_tx_qstop++;
 			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
 			break;
 		}
-		/*
-		 * Poll the management queue for frames; they
-		 * have priority over normal data frames.
-		 */
-		IF_DEQUEUE(&ic->ic_mgtq, m);
+
+		STAILQ_INIT(&frags);
+		IFQ_DEQUEUE(&ifp->if_snd, m);
 		if (m == NULL) {
 			/*
-			 * No data frames go out unless we're associated.
+			 * The q was emptied while we blocked,
+			 * this can happen when we're preempted.
 			 */
-			if (ic->ic_state != IEEE80211_S_RUN) {
-				DPRINTF(sc, ATH_DEBUG_XMIT,
-				    "%s: discard data packet, state %s\n",
-				    __func__,
-				    ieee80211_state_name[ic->ic_state]);
-				sc->sc_stats.ast_tx_discard++;
-				ATH_TXBUF_LOCK(sc);
-				STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
-				ATH_TXBUF_UNLOCK(sc);
-				break;
-			}
-			IFQ_DRV_DEQUEUE(&ifp->if_snd, m);	/* XXX: LOCK */
-			if (m == NULL) {
-				ATH_TXBUF_LOCK(sc);
-				STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
-				ATH_TXBUF_UNLOCK(sc);
-				break;
-			}
+			ni = NULL;
+			goto reclaim;
+		}
+		ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
+		pri = M_WME_GETAC(m);
+		txq = sc->sc_ac2q[pri];
+		if (ni->ni_ath_flags & IEEE80211_NODE_FF) {
 			/*
-			 * Cancel any background scan.
+			 * Check queue length; if too deep drop this
+			 * frame (tail drop considered good).
 			 */
-			if (ic->ic_flags & IEEE80211_F_SCAN)
-				ieee80211_cancel_scan(ic);
-
-			STAILQ_INIT(&frags);
-			/*
-			 * Find the node for the destination so we can do
-			 * things like power save and fast frames aggregation.
-			 */
-			if (m->m_len < sizeof(struct ether_header) &&
-			   (m = m_pullup(m, sizeof(struct ether_header))) == NULL) {
-				ic->ic_stats.is_tx_nobuf++;	/* XXX */
-				ni = NULL;
-				goto bad;
-			}
-			eh = mtod(m, struct ether_header *);
-			ni = ieee80211_find_txnode(ic, eh->ether_dhost);
-			if (ni == NULL) {
-				/* NB: ieee80211_find_txnode does stat+msg */
+			if (txq->axq_depth >= sc->sc_fftxqmax) {
+				DPRINTF(sc, ATH_DEBUG_FF,
+				    "[%s] tail drop on q %u depth %u\n",
+				    ether_sprintf(ni->ni_macaddr),
+				    txq->axq_qnum, txq->axq_depth);
+				sc->sc_stats.ast_tx_qfull++;
 				m_freem(m);
-				goto bad;
-			}
-			if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
-			    (m->m_flags & M_PWR_SAV) == 0) {
-				/*
-				 * Station in power save mode; pass the frame
-				 * to the 802.11 layer and continue.  We'll get
-				 * the frame back when the time is right.
-				 */
-				ieee80211_pwrsave(ni, m);
 				goto reclaim;
 			}
-			/* calculate priority so we can find the tx queue */
-			if (ieee80211_classify(ic, m, ni)) {
-				DPRINTF(sc, ATH_DEBUG_XMIT,
-					"%s: discard, classification failure\n",
-					__func__);
-				m_freem(m);
-				goto bad;
-			}
-			pri = M_WME_GETAC(m);
-			txq = sc->sc_ac2q[pri];
-			if (ni->ni_ath_flags & IEEE80211_NODE_FF) {
-				/*
-				 * Check queue length; if too deep drop this
-				 * frame (tail drop considered good).
-				 */
-				if (txq->axq_depth >= sc->sc_fftxqmax) {
-					DPRINTF(sc, ATH_DEBUG_FF,
-					    "[%s] tail drop on q %u depth %u\n",
-					    ether_sprintf(ni->ni_macaddr),
-					    txq->axq_qnum, txq->axq_depth);
-					sc->sc_stats.ast_tx_qfull++;
-					m_freem(m);
-					goto reclaim;
-				}
-				m = ath_ff_check(sc, txq, bf, m, ni);
-				if (m == NULL) {
-					/* NB: ni ref & bf held on stageq */
-					continue;
-				}
-			}
-			ifp->if_opackets++;
-			BPF_MTAP(ifp, m);
-			/*
-			 * Encapsulate the packet in prep for transmission.
-			 */
-			m = ieee80211_encap(ic, m, ni);
+			m = ath_ff_check(sc, txq, bf, m, ni);
 			if (m == NULL) {
-				DPRINTF(sc, ATH_DEBUG_XMIT,
-					"%s: encapsulation failure\n",
-					__func__);
-				sc->sc_stats.ast_tx_encap++;
-				goto bad;
+				/* NB: ni ref & bf held on stageq */
+				continue;
 			}
-			/*
-			 * Check for fragmentation.  If this frame
-			 * has been broken up verify we have enough
-			 * buffers to send all the fragments so all
-			 * go out or none...
-			 */
-			if ((m->m_flags & M_FRAG) && 
-			    !ath_txfrag_setup(sc, &frags, m, ni)) {
-				DPRINTF(sc, ATH_DEBUG_XMIT,
-				    "%s: out of txfrag buffers\n", __func__);
-				ic->ic_stats.is_tx_nobuf++;	/* XXX */
-				ath_freetx(m);
-				goto bad;
-			}
-		} else {
-			/*
-			 * 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 *) m->m_pkthdr.rcvif;
-			m->m_pkthdr.rcvif = NULL;
-
-			wh = mtod(m, struct ieee80211_frame *);
-			if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
-			    IEEE80211_FC0_SUBTYPE_PROBE_RESP) {
-				/* fill time stamp */
-				u_int64_t tsf;
-				u_int32_t *tstamp;
-
-				tsf = ath_hal_gettsf64(ah);
-				/* XXX: adjust 100us delay to xmit */
-				tsf += 100;
-				tstamp = (u_int32_t *)&wh[1];
-				tstamp[0] = htole32(tsf & 0xffffffff);
-				tstamp[1] = htole32(tsf >> 32);
-			}
-			sc->sc_stats.ast_tx_mgmt++;
+		}
+		ifp->if_opackets++;
+		/*
+		 * Encapsulate the packet in prep for transmission.
+		 */
+		m = ieee80211_encap(ni, m);
+		if (m == NULL) {
+			DPRINTF(sc, ATH_DEBUG_XMIT,
+			    "%s: encapsulation failure\n", __func__);
+			sc->sc_stats.ast_tx_encap++;
+			goto bad;
+		}
+		/*
+		 * Check for fragmentation.  If this frame
+		 * has been broken up verify we have enough
+		 * buffers to send all the fragments so all
+		 * go out or none...
+		 */
+		if ((m->m_flags & M_FRAG) && 
+		    !ath_txfrag_setup(sc, &frags, m, ni)) {
+			DPRINTF(sc, ATH_DEBUG_XMIT,
+			    "%s: out of txfrag buffers\n", __func__);
+			ic->ic_stats.is_tx_nobuf++;	/* XXX */
+			ath_freetx(m);
+			goto bad;
 		}
-
 	nextfrag:
 		/*
 		 * Pass the frame to the h/w for transmission.
@@ -1735,11 +1736,11 @@
 			 * Beware of state changing between frags.
 			 * XXX check sta power-save state?
 			 */
-			if (ic->ic_state != IEEE80211_S_RUN) {
+			if (ni->ni_vap->iv_state != IEEE80211_S_RUN) {
 				DPRINTF(sc, ATH_DEBUG_XMIT,
 				    "%s: flush fragmented packet, state %s\n",
 				    __func__,
-				    ieee80211_state_name[ic->ic_state]);
+				    ieee80211_state_name[ni->ni_vap->iv_state]);
 				ath_freetx(next);
 				goto reclaim;
 			}
@@ -1751,7 +1752,6 @@
 		}
 
 		ifp->if_timer = 5;
-		ic->ic_lastdata = ticks;
 #if 0
 		/*
 		 * Flush stale frames from the fast-frame staging queue.
@@ -1765,30 +1765,9 @@
 static int
 ath_media_change(struct ifnet *ifp)
 {
-#define	IS_UP(ifp) \
-	((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
-	int error;
-
-	error = ieee80211_media_change(ifp);
-	if (error == ENETRESET) {
-		struct ath_softc *sc = ifp->if_softc;
-		struct ieee80211com *ic = &sc->sc_ic;
-
-		if (ic->ic_opmode == IEEE80211_M_AHDEMO) {
-			/* 
-			 * Adhoc demo mode is just ibss mode w/o beacons
-			 * (mostly).  The hal knows nothing about it;
-			 * tell it we're operating in ibss mode.
-			 */
-			sc->sc_opmode = HAL_M_IBSS;
-		} else
-			sc->sc_opmode = ic->ic_opmode;
-		if (IS_UP(ifp))
-			ath_init(sc);		/* XXX lose error */
-		error = 0;
-	}
-	return error;
-#undef IS_UP
+	int error = ieee80211_media_change(ifp);
+	/* NB: only the fixed rate can change and that doesn't need a reset */
+	return (error == ENETRESET ? 0 : error);
 }
 
 #ifdef ATH_DEBUG
@@ -2091,10 +2070,10 @@
  * 64 entries.
  */
 static int
-ath_key_alloc(struct ieee80211com *ic, const struct ieee80211_key *k,
+ath_key_alloc(struct ieee80211vap *vap, const struct ieee80211_key *k,
 	ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
 {
-	struct ath_softc *sc = ic->ic_ifp->if_softc;
+	struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
 
 	/*
 	 * Group key allocation must be handled specially for
@@ -2108,8 +2087,8 @@
 	 * multi-station operation.
 	 */
 	if ((k->wk_flags & IEEE80211_KEY_GROUP) && !sc->sc_mcastkey) {
-		if (!(&ic->ic_nw_keys[0] <= k &&
-		      k < &ic->ic_nw_keys[IEEE80211_WEP_NKID])) {
+		if (!(&vap->iv_nw_keys[0] <= k &&
+		      k < &vap->iv_nw_keys[IEEE80211_WEP_NKID])) {
 			/* should not happen */
 			DPRINTF(sc, ATH_DEBUG_KEYCACHE,
 				"%s: bogus group key\n", __func__);
@@ -2119,7 +2098,7 @@
 		 * XXX we pre-allocate the global keys so
 		 * have no way to check if they've already been allocated.
 		 */
-		*keyix = *rxkeyix = k - ic->ic_nw_keys;
+		*keyix = *rxkeyix = k - vap->iv_nw_keys;
 		return 1;
 	}
 
@@ -2148,9 +2127,9 @@
  * Delete an entry in the key cache allocated by ath_key_alloc.
  */
 static int
-ath_key_delete(struct ieee80211com *ic, const struct ieee80211_key *k)
+ath_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
 {
-	struct ath_softc *sc = ic->ic_ifp->if_softc;
+	struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
 	struct ath_hal *ah = sc->sc_ah;
 	const struct ieee80211_cipher *cip = k->wk_cipher;
 	u_int keyix = k->wk_keyix;
@@ -2188,12 +2167,12 @@
  * slot(s) must already have been allocated by ath_key_alloc.
  */
 static int
-ath_key_set(struct ieee80211com *ic, const struct ieee80211_key *k,
+ath_key_set(struct ieee80211vap *vap, const struct ieee80211_key *k,
 	const u_int8_t mac[IEEE80211_ADDR_LEN])
 {
-	struct ath_softc *sc = ic->ic_ifp->if_softc;
+	struct ath_softc *sc = vap->iv_ic->ic_ifp->if_softc;
 
-	return ath_keyset(sc, k, mac, ic->ic_bss);
+	return ath_keyset(sc, k, mac, vap->iv_bss);
 }
 
 /*
@@ -2203,9 +2182,9 @@
  * uses that originate in the driver.
  */
 static void
-ath_key_update_begin(struct ieee80211com *ic)
+ath_key_update_begin(struct ieee80211vap *vap)
 {
-	struct ifnet *ifp = ic->ic_ifp;
+	struct ifnet *ifp = vap->iv_ic->ic_ifp;
 	struct ath_softc *sc = ifp->if_softc;
 
 	DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__);
@@ -2216,9 +2195,9 @@
 }
 
 static void
-ath_key_update_end(struct ieee80211com *ic)
+ath_key_update_end(struct ieee80211vap *vap)
 {
-	struct ifnet *ifp = ic->ic_ifp;
+	struct ifnet *ifp = vap->iv_ic->ic_ifp;
 	struct ath_softc *sc = ifp->if_softc;
 
 	DPRINTF(sc, ATH_DEBUG_KEYCACHE, "%s:\n", __func__);
@@ -2233,8 +2212,6 @@
  * operating mode and state:
  *
  * o always accept unicast, broadcast, and multicast traffic
- * o maintain current state of phy error reception (the hal
- *   may enable phy error frames for noise immunity work)
  * o probe request frames are accepted only when operating in
  *   hostap, adhoc, or monitor modes
  * o enable promiscuous mode according to the interface state
@@ -2246,31 +2223,68 @@
  *   - when scanning
  * o accept control frames:
  *   - when in monitor mode
+ * XXX BAR frames for 11n
  */
 static u_int32_t
 ath_calcrxfilter(struct ath_softc *sc)
 {
-#define	RX_FILTER_PRESERVE	(HAL_RX_FILTER_PHYERR | HAL_RX_FILTER_PHYRADAR)
 	struct ieee80211com *ic = &sc->sc_ic;
-	struct ath_hal *ah = sc->sc_ah;
 	struct ifnet *ifp = sc->sc_ifp;
 	u_int32_t rfilt;
 
-	rfilt = (ath_hal_getrxfilter(ah) & RX_FILTER_PRESERVE)
-	      | HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST;
+	rfilt = HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST;
 	if (ic->ic_opmode != IEEE80211_M_STA)
 		rfilt |= HAL_RX_FILTER_PROBEREQ;
 	if (ic->ic_opmode != IEEE80211_M_HOSTAP &&
 	    (ifp->if_flags & IFF_PROMISC))
 		rfilt |= HAL_RX_FILTER_PROM;
 	if (ic->ic_opmode == IEEE80211_M_STA ||
-	    ic->ic_opmode == IEEE80211_M_IBSS ||
+	    sc->sc_opmode == HAL_M_IBSS ||
 	    sc->sc_scanning)
 		rfilt |= HAL_RX_FILTER_BEACON;
 	if (ic->ic_opmode == IEEE80211_M_MONITOR)
 		rfilt |= HAL_RX_FILTER_CONTROL;
+	if (ic->ic_opmode == IEEE80211_M_STA &&
+	    !sc->sc_needmib && !sc->sc_scanning)
+		rfilt |= HAL_RX_FILTER_PHYERR;
 	return rfilt;
-#undef RX_FILTER_PRESERVE
+}
+
+/*
+ * Merge multicast address from all vap's to form the hardware
+ * filter.  Ideally we should only inspect our own list and the
+ * 802.11 layer would merge for us but that's bit difficult so
+ * for now we put the onus on the driver.
+ */
+static void
+ath_merge_mcast(struct ath_softc *sc, u_int32_t mfilt[2])
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct ieee80211vap *vap;
+
+	mfilt[0] = mfilt[1] = 0;
+	/* XXX locking */
+	TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
+		struct ifnet *ifp = vap->iv_ifp;
+		struct ifmultiaddr *ifma;
+
+		IF_ADDR_LOCK(ifp);
+		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
+			caddr_t dl;
+			u_int32_t val;
+			u_int8_t pos;
+
+			/* calculate XOR of eight 6bit values */
+			dl = LLADDR((struct sockaddr_dl *) ifma->ifma_addr);
+			val = LE_READ_4(dl + 0);
+			pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
+			val = LE_READ_4(dl + 3);
+			pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
+			pos &= 0x3f;
+			mfilt[pos / 32] |= (1 << (pos % 32));
+		}
+		IF_ADDR_UNLOCK(ifp);
+	}
 }
 
 static void
@@ -2279,9 +2293,7 @@
 	struct ieee80211com *ic = &sc->sc_ic;

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


More information about the p4-projects mailing list