Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 30 Sep 2012 22:39:35 -0700
From:      Adrian Chadd <adrian@freebsd.org>
To:        freebsd-wireless@freebsd.org
Subject:   [RFC] Methodize the net8021 power save hooks
Message-ID:  <CAJ-VmonvY1RyoruDeDL7NNXDgv-=iOEZ7S_teUu67iiAQ661Nw@mail.gmail.com>

next in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
Hi,

I'm about to start tinkering with ath(4) power save support and I'd
like to introduce some net80211 changes to support this.

* Methodize the STA and node power save functions, so the driver can
stop/start the software queues as needed;
* Push PS-POLL frame leaking into a method, so the driver can override
this if something is in a local queue.

Since the driver may have some software queued frames for it, the
driver needs to be able to leak these frames out correctly before the
power-save queue frames are transmitted.

My initial change to ath(4) will be to pause and unpause the node when
the net80211 stack calls iv_node_ps() so the driver doesn't bother
transmitting to a node that's asleep.

There's a bunch of other needed changes that I'll then do in some
follow-up work:

* The TIM/ATIM doesn't know about what's in the software queue, so I'm
going to have to introduce some further methods to allow the driver to
update the TIM/ATIM as needed;
* There's a M_PWR_SAV mbuf flag that means "this came from the power
save queue". I need to see what/how drivers should treat this;
* When a frame is sent via the PS-POLL method whilst a STA is asleep,
the TIDs may be paused and as such the node won't transmit. In this
case, frames pushed from the power save queue to the driver should
immediately be transmitted, rather than punted to the software queue.
* I also need to verify that the CABQ traffic is being set correctly-
ie, the CABQ traffic all has the MORE bit appropriately set or
cleared.
* For nodes that are being sent PS-POLL (and later, uAPSD) delivered
frames, they should be put "next" on the TX queue, ahead of any other
TIDs that are being scheduled. That way their frame goes out next (or
has a good chance to), versus being behind all the other currently
transmitting (but not in power save) nodes. This should allow the
device to quickly receive the frame and go back to sleep.
I'm going to leave the next set of changes until I've done the first
bit of work and verified it's working. I'll likely make that behaviour
configurable because I'm worried that the incomplete PS-POLL upgrades
will break mobile devices that try to stay in PS-POLL and "leak"
frames (versus things like my MBP that just go in/out of power save
and don't use PS-POLL at all.)



adrian

[-- Attachment #2 --]
Index: UPDATING
===================================================================
--- UPDATING	(revision 241081)
+++ UPDATING	(working copy)
@@ -24,6 +24,11 @@
 	disable the most expensive debugging functionality run
 	"ln -s 'abort:false,junk:false' /etc/malloc.conf".)
 
+20121001:
+	The net80211(4) ABI has been changed to allow for improved driver
+	PS-POLL and power-save support.  All wireless drivers need to be
+	recompiled to work with the new kernel.
+
 20120908:
 	The pf(4) packet filter ABI has been changed. pfctl(8) and
 	snmp_pf module need to be recompiled to work with new kernel.
Index: sys/net80211/ieee80211_sta.c
===================================================================
--- sys/net80211/ieee80211_sta.c	(revision 240968)
+++ sys/net80211/ieee80211_sta.c	(working copy)
@@ -402,7 +402,7 @@
 			    arg == IEEE80211_FC0_SUBTYPE_ASSOC_RESP);
 			break;
 		case IEEE80211_S_SLEEP:
-			ieee80211_sta_pwrsave(vap, 0);
+			vap->iv_sta_ps(vap, 0);
 			break;
 		default:
 			goto invalid;
@@ -438,7 +438,7 @@
 			goto invalid;
 		break;
 	case IEEE80211_S_SLEEP:
-		ieee80211_sta_pwrsave(vap, 1);
+		vap->iv_sta_ps(vap, 1);
 		break;
 	default:
 	invalid:
@@ -1396,7 +1396,7 @@
 					 * we are expecting data.
 					 */
 					ic->ic_lastdata = ticks;
-					ieee80211_sta_pwrsave(vap, 0);
+					vap->iv_sta_ps(vap, 0);
 				}
 #endif
 				ni->ni_dtim_count = tim->tim_count;
Index: sys/net80211/ieee80211_power.c
===================================================================
--- sys/net80211/ieee80211_power.c	(revision 240968)
+++ sys/net80211/ieee80211_power.c	(working copy)
@@ -69,6 +69,8 @@
 		vap->iv_update_ps = ieee80211_update_ps;
 		vap->iv_set_tim = ieee80211_set_tim;
 	}
+	vap->iv_node_ps = ieee80211_node_pwrsave;
+	vap->iv_sta_ps = ieee80211_sta_pwrsave;
 }
 
 void
Index: sys/net80211/ieee80211_var.h
===================================================================
--- sys/net80211/ieee80211_var.h	(revision 240968)
+++ sys/net80211/ieee80211_var.h	(working copy)
@@ -486,6 +486,11 @@
 	/* power save handling */
 	void			(*iv_update_ps)(struct ieee80211vap *, int);
 	int			(*iv_set_tim)(struct ieee80211_node *, int);
+	void			(*iv_node_ps)(struct ieee80211_node *, int);
+	void			(*iv_sta_ps)(struct ieee80211vap *, int);
+	void			(*iv_recv_pspoll)(struct ieee80211_node *,
+				    struct mbuf *);
+
 	/* state machine processing */
 	int			(*iv_newstate)(struct ieee80211vap *,
 				    enum ieee80211_state, int);
Index: sys/net80211/ieee80211_hostap.c
===================================================================
--- sys/net80211/ieee80211_hostap.c	(revision 240968)
+++ sys/net80211/ieee80211_hostap.c	(working copy)
@@ -73,7 +73,6 @@
 static void hostap_recv_mgmt(struct ieee80211_node *, struct mbuf *,
 	    int subtype, int rssi, int nf);
 static void hostap_recv_ctl(struct ieee80211_node *, struct mbuf *, int);
-static void hostap_recv_pspoll(struct ieee80211_node *, struct mbuf *);
 
 void
 ieee80211_hostap_attach(struct ieee80211com *ic)
@@ -100,6 +99,7 @@
 	vap->iv_recv_ctl = hostap_recv_ctl;
 	vap->iv_opdetach = hostap_vdetach;
 	vap->iv_deliver_data = hostap_deliver_data;
+	vap->iv_recv_pspoll = ieee80211_recv_pspoll;
 }
 
 static void
@@ -645,7 +645,7 @@
 		 */
 		if (((wh->i_fc[1] & IEEE80211_FC1_PWR_MGT) ^
 		    (ni->ni_flags & IEEE80211_NODE_PWR_MGT)))
-			ieee80211_node_pwrsave(ni,
+			vap->iv_node_ps(ni,
 				wh->i_fc[1] & IEEE80211_FC1_PWR_MGT);
 		/*
 		 * For 4-address packets handle WDS discovery
@@ -2240,7 +2240,7 @@
 {
 	switch (subtype) {
 	case IEEE80211_FC0_SUBTYPE_PS_POLL:
-		hostap_recv_pspoll(ni, m);
+		ni->ni_vap->iv_recv_pspoll(ni, m);
 		break;
 	case IEEE80211_FC0_SUBTYPE_BAR:
 		ieee80211_recv_bar(ni, m);
@@ -2251,8 +2251,8 @@
 /*
  * Process a received ps-poll frame.
  */
-static void
-hostap_recv_pspoll(struct ieee80211_node *ni, struct mbuf *m0)
+void
+ieee80211_recv_pspoll(struct ieee80211_node *ni, struct mbuf *m0)
 {
 	struct ieee80211vap *vap = ni->ni_vap;
 	struct ieee80211_frame_min *wh;
Index: sys/net80211/ieee80211_power.h
===================================================================
--- sys/net80211/ieee80211_power.h	(revision 240968)
+++ sys/net80211/ieee80211_power.h	(working copy)
@@ -71,6 +71,11 @@
 struct mbuf *ieee80211_node_psq_dequeue(struct ieee80211_node *ni, int *qlen);
 int	ieee80211_node_psq_drain(struct ieee80211_node *);
 int	ieee80211_node_psq_age(struct ieee80211_node *);
+
+/*
+ * Don't call these directly from the stack; they are vap methods
+ * that should be overridden.
+ */
 int	ieee80211_pwrsave(struct ieee80211_node *, struct mbuf *);
 void	ieee80211_node_pwrsave(struct ieee80211_node *, int enable);
 void	ieee80211_sta_pwrsave(struct ieee80211vap *, int enable);
Index: sys/net80211/ieee80211_hostap.h
===================================================================
--- sys/net80211/ieee80211_hostap.h	(revision 240968)
+++ sys/net80211/ieee80211_hostap.h	(working copy)
@@ -32,4 +32,10 @@
  */
 void	ieee80211_hostap_attach(struct ieee80211com *);
 void	ieee80211_hostap_detach(struct ieee80211com *);
+
+/*
+ * This method can be overridden
+ */
+void ieee80211_recv_pspoll(struct ieee80211_node *, struct mbuf *);
+
 #endif /* !_NET80211_IEEE80211_HOSTAP_H_ */
Index: sys/net80211/ieee80211_scan.c
===================================================================
--- sys/net80211/ieee80211_scan.c	(revision 240968)
+++ sys/net80211/ieee80211_scan.c	(working copy)
@@ -866,7 +866,7 @@
 	    vap->iv_state == IEEE80211_S_RUN) {
 		if ((vap->iv_bss->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) {
 			/* Enable station power save mode */
-			ieee80211_sta_pwrsave(vap, 1);
+			vap->iv_sta_ps(vap, 1);
 			/*
 			 * Use an 1ms delay so the null data frame has a chance
 			 * to go out.
@@ -1047,7 +1047,7 @@
 	 * waiting for us.
 	 */
 	if (scandone) {
-		ieee80211_sta_pwrsave(vap, 0);
+		vap->iv_sta_ps(vap, 0);
 		if (ss->ss_next >= ss->ss_last) {
 			ieee80211_notify_scan_done(vap);
 			ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN;
Index: sys/net80211/ieee80211_adhoc.c
===================================================================
--- sys/net80211/ieee80211_adhoc.c	(revision 240968)
+++ sys/net80211/ieee80211_adhoc.c	(working copy)
@@ -242,7 +242,7 @@
 			ic->ic_newassoc(ni, ostate != IEEE80211_S_RUN);
 		break;
 	case IEEE80211_S_SLEEP:
-		ieee80211_sta_pwrsave(vap, 0);
+		vap->iv_sta_ps(vap, 0);
 		break;
 	default:
 	invalid:

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAJ-VmonvY1RyoruDeDL7NNXDgv-=iOEZ7S_teUu67iiAQ661Nw>