Date: Sat, 23 Feb 2008 01:40:28 GMT From: Sam Leffler <sam@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 136005 for review Message-ID: <200802230140.m1N1eSRQ095778@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=136005 Change 136005 by sam@sam_ebb on 2008/02/23 01:39:39 Update power save support: o change iv_set_tim to return an indication whether the TIM state changed for the station so drivers can easily tell if they need to push the change to their device o add iv_update_ps callback to notify drivers when the power occupancy of the BSS changed; useful for drivers that want to notify outboard devices when to buffer mcast frames and also should be used to flush any multicast frames being held for xmit at DTIM o call if_start on the vap when flushing frames from the ps q o reorder operations in ieee80211_node_pwrsave so when a station exits ps the beacon state is updated before the ps q is flushed; this is intended to guard against beacons going out with stale TIM state Affected files ... .. //depot/projects/vap/sys/net80211/ieee80211_power.c#10 edit .. //depot/projects/vap/sys/net80211/ieee80211_var.h#30 edit Differences ... ==== //depot/projects/vap/sys/net80211/ieee80211_power.c#10 (text+ko) ==== @@ -45,7 +45,8 @@ #include <net/bpf.h> -static void ieee80211_set_tim(struct ieee80211_node *ni, int set); +static void ieee80211_update_ps(struct ieee80211vap *, int); +static int ieee80211_set_tim(struct ieee80211_node *, int); MALLOC_DEFINE(M_80211_POWER, "80211power", "802.11 power save state"); @@ -65,6 +66,7 @@ if (vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_IBSS) { /* NB: driver should override */ + vap->iv_update_ps = ieee80211_update_ps; vap->iv_set_tim = ieee80211_set_tim; } } @@ -155,14 +157,27 @@ } /* + * Handle a change in the PS station occupancy. + */ +static void +ieee80211_update_ps(struct ieee80211vap *vap, int nsta) +{ + + KASSERT(vap->iv_opmode == IEEE80211_M_HOSTAP || + vap->iv_opmode == IEEE80211_M_IBSS, + ("operating mode %u", vap->iv_opmode)); +} + +/* * Indicate whether there are frames queued for a station in power-save mode. */ -static void +static int ieee80211_set_tim(struct ieee80211_node *ni, int set) { struct ieee80211vap *vap = ni->ni_vap; struct ieee80211com *ic = ni->ni_ic; uint16_t aid; + int changed; KASSERT(vap->iv_opmode == IEEE80211_M_HOSTAP || vap->iv_opmode == IEEE80211_M_IBSS, @@ -173,7 +188,8 @@ ("bogus aid %u, max %u", aid, vap->iv_max_aid)); IEEE80211_LOCK(ic); - if (set != (isset(vap->iv_tim_bitmap, aid) != 0)) { + changed = (set != (isset(vap->iv_tim_bitmap, aid) != 0)); + if (changed) { if (set) { setbit(vap->iv_tim_bitmap, aid); vap->iv_ps_pending++; @@ -185,6 +201,8 @@ vap->iv_update_beacon(vap, IEEE80211_BEACON_TIM); } IEEE80211_UNLOCK(ic); + + return changed; } /* @@ -263,9 +281,10 @@ IEEE80211_NODE_SAVEQ_UNLOCK(ni); if (mhead != NULL) { /* XXX need different driver interface */ - /* XXX bypasses q max */ + /* XXX bypasses q max and OACTIVE */ struct ifnet *ifp = ni->ni_vap->iv_ifp; IF_PREPEND_LIST(&ifp->if_snd, mhead, mtail, mcount); + if_start(ifp); } } @@ -276,26 +295,38 @@ ieee80211_node_pwrsave(struct ieee80211_node *ni, int enable) { struct ieee80211vap *vap = ni->ni_vap; + int update; + update = 0; if (enable) { - if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) + if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) { vap->iv_ps_sta++; + update = 1; + } ni->ni_flags |= IEEE80211_NODE_PWR_MGT; IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, "power save mode on, %u sta's in ps mode", vap->iv_ps_sta); - return; - } - if (ni->ni_flags & IEEE80211_NODE_PWR_MGT) - vap->iv_ps_sta--; - ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT; - IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, - "power save mode off, %u sta's in ps mode", vap->iv_ps_sta); - /* XXX if no stations in ps mode, flush mc frames */ + if (update) + vap->iv_update_ps(vap, vap->iv_ps_sta); + } else { + if (ni->ni_flags & IEEE80211_NODE_PWR_MGT) { + vap->iv_ps_sta--; + update = 1; + } + ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT; + IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, + "power save mode off, %u sta's in ps mode", vap->iv_ps_sta); - pwrsave_flushq(ni); - if (vap->iv_set_tim != NULL) - vap->iv_set_tim(ni, 0); + /* NB: order here is intentional so TIM is clear before flush */ + if (vap->iv_set_tim != NULL) + vap->iv_set_tim(ni, 0); + if (update) { + /* NB if no sta's in ps, driver should flush mc q */ + vap->iv_update_ps(vap, vap->iv_ps_sta); + } + pwrsave_flushq(ni); + } } /* ==== //depot/projects/vap/sys/net80211/ieee80211_var.h#30 (text+ko) ==== @@ -343,7 +343,6 @@ uint8_t iv_dtim_period; /* DTIM period */ uint8_t iv_dtim_count; /* DTIM count from last bcn */ /* set/unset aid pwrsav state */ - void (*iv_set_tim)(struct ieee80211_node *, int); int iv_csa_count; /* count for doing CSA */ struct ieee80211_node *iv_bss; /* information for this node */ @@ -401,6 +400,9 @@ int (*iv_reset)(struct ieee80211vap *, u_long); /* [schedule] beacon frame update */ void (*iv_update_beacon)(struct ieee80211vap *, int); + /* power save handling */ + void (*iv_update_ps)(struct ieee80211vap *, int); + int (*iv_set_tim)(struct ieee80211_node *, int); /* state machine processing */ int (*iv_newstate)(struct ieee80211vap *, enum ieee80211_state, int);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200802230140.m1N1eSRQ095778>