PERFORCE change 77599 for review
Sam Leffler
sam at FreeBSD.org
Fri May 27 17:41:50 PDT 2005
http://perforce.freebsd.org/chv.cgi?CH=77599
Change 77599 by sam at sam_ebb on 2005/05/28 00:41:14
Checkpoint sta-mode power save support; mostly works but needs
some tweaking for bg scanning:
o add a new SLEEP state and use the state machine to hook into
the driver to effect pwr save operation of the device
o add power save polling callback from inactivity timer; use
this to drop into power save mode when inactive
o mark null data frame sent to ap on entering pwr save mode so
driver can identify when it should enable pwr save operation
for the device (must be deferred until frame goes is acked)
Also:
o clear tim after flushing ps q for an associated sta that drops
out of pwr save mode
o when marking an ap down send a disassoc _and_ clear the sta
from the table to insure the reference count goes to zero
Affected files ...
.. //depot/projects/vap/sys/net80211/ieee80211_freebsd.h#8 edit
.. //depot/projects/vap/sys/net80211/ieee80211_input.c#18 edit
.. //depot/projects/vap/sys/net80211/ieee80211_ioctl.c#14 edit
.. //depot/projects/vap/sys/net80211/ieee80211_node.c#12 edit
.. //depot/projects/vap/sys/net80211/ieee80211_output.c#15 edit
.. //depot/projects/vap/sys/net80211/ieee80211_power.c#3 edit
.. //depot/projects/vap/sys/net80211/ieee80211_power.h#2 edit
.. //depot/projects/vap/sys/net80211/ieee80211_proto.c#12 edit
.. //depot/projects/vap/sys/net80211/ieee80211_proto.h#7 edit
Differences ...
==== //depot/projects/vap/sys/net80211/ieee80211_freebsd.h#8 (text+ko) ====
@@ -150,6 +150,7 @@
#define M_LINK0 M_PROTO1 /* WEP requested */
#define M_PWR_SAV M_PROTO4 /* bypass PS handling */
#define M_FF M_PROTO5 /* fast-frame */
+#define M_PWR_DOWN 0x20000 /* power down null data frame */
/*
* Encode WME access control bits in the PROTO flags.
* This is safe since it's passed directly in to the
==== //depot/projects/vap/sys/net80211/ieee80211_input.c#18 (text+ko) ====
@@ -1082,7 +1082,7 @@
}
switch (vap->iv_opmode) {
case IEEE80211_M_IBSS:
- if (vap->iv_state != IEEE80211_S_RUN ||
+ if (vap->iv_state < IEEE80211_S_RUN ||
seq != IEEE80211_AUTH_OPEN_REQUEST) {
vap->iv_stats.is_rx_bad_auth++;
return;
@@ -1097,7 +1097,7 @@
break;
case IEEE80211_M_HOSTAP:
- if (vap->iv_state != IEEE80211_S_RUN ||
+ if (vap->iv_state < IEEE80211_S_RUN ||
seq != IEEE80211_AUTH_OPEN_REQUEST) {
vap->iv_stats.is_rx_bad_auth++;
return;
@@ -1277,7 +1277,7 @@
"bad operating mode %u", vap->iv_opmode);
return;
case IEEE80211_M_HOSTAP:
- if (vap->iv_state != IEEE80211_S_RUN) {
+ if (vap->iv_state < IEEE80211_S_RUN) {
IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_AUTH,
ni->ni_macaddr, "shared key auth",
"bad state %u", vap->iv_state);
@@ -2402,7 +2402,7 @@
u_int8_t rate;
if (vap->iv_opmode == IEEE80211_M_STA ||
- vap->iv_state != IEEE80211_S_RUN) {
+ vap->iv_state < IEEE80211_S_RUN) {
vap->iv_stats.is_rx_mgtdiscard++;
return;
}
@@ -2557,7 +2557,7 @@
u_int8_t reason;
if (vap->iv_opmode != IEEE80211_M_HOSTAP ||
- vap->iv_state != IEEE80211_S_RUN) {
+ vap->iv_state < IEEE80211_S_RUN) {
vap->iv_stats.is_rx_mgtdiscard++;
return;
}
@@ -2904,7 +2904,7 @@
case IEEE80211_FC0_SUBTYPE_DISASSOC: {
u_int16_t reason;
- if (vap->iv_state != IEEE80211_S_RUN &&
+ if (vap->iv_state < IEEE80211_S_RUN &&
vap->iv_state != IEEE80211_S_ASSOC &&
vap->iv_state != IEEE80211_S_AUTH) {
vap->iv_stats.is_rx_mgtdiscard++;
==== //depot/projects/vap/sys/net80211/ieee80211_ioctl.c#14 (text+ko) ====
@@ -1511,6 +1511,7 @@
case IEEE80211_POWERSAVE_OFF:
if (vap->iv_flags & IEEE80211_F_PMGTON) {
vap->iv_flags &= ~IEEE80211_F_PMGTON;
+ ieee80211_syncflag(ic, IEEE80211_F_PMGTON);
error = ENETRESET;
}
break;
@@ -1519,6 +1520,7 @@
error = EINVAL;
else if ((vap->iv_flags & IEEE80211_F_PMGTON) == 0) {
vap->iv_flags |= IEEE80211_F_PMGTON;
+ ieee80211_syncflag(ic, IEEE80211_F_PMGTON);
error = ENETRESET;
}
break;
@@ -1911,7 +1913,7 @@
if ((parent->if_flags & IFF_UP) == 0) {
parent->if_flags |= IFF_UP;
error = parent->if_ioctl(parent, cmd, data);
- } else if (vap->iv_state != IEEE80211_S_RUN)
+ } else if (vap->iv_state < IEEE80211_S_RUN)
ifp->if_init(ifp->if_softc);
} else {
ieee80211_stop(ifp); /* stop ourself */
==== //depot/projects/vap/sys/net80211/ieee80211_node.c#12 (text+ko) ====
@@ -1293,6 +1293,7 @@
ieee80211_scan_timeout(ic);
ieee80211_timeout_stations(&ic->ic_sta);
+ ieee80211_power_poll(ic);
callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT * hz,
ieee80211_node_timeout, ic);
==== //depot/projects/vap/sys/net80211/ieee80211_output.c#15 (text+ko) ====
@@ -217,20 +217,26 @@
/* NB: parent must be up and running */
if ((parent->if_flags & (IFF_RUNNING|IFF_UP)) != (IFF_RUNNING|IFF_UP))
return;
- for (;;) {
+ if (vap->iv_state == IEEE80211_S_SLEEP) {
/*
- * No data frames go out unless we're running.
+ * Wakeup device for transmit.
*/
- if (vap->iv_state != IEEE80211_S_RUN) {
- IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
- "%s: ignore data packet, state %u\n",
- __func__, vap->iv_state);
+ ieee80211_new_state(vap, IEEE80211_S_RUN, 0);
+ }
+ /*
+ * No data frames go out unless we're running.
+ */
+ if (vap->iv_state != IEEE80211_S_RUN) {
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT,
+ "%s: ignore data packet, state %u\n",
+ __func__, vap->iv_state);
#if 0
- vap->iv_stats.ist_tx_discard++;
+ vap->iv_stats.ist_tx_discard++;
#endif
- ifp->if_flags |= IFF_OACTIVE;
- break;
- }
+ ifp->if_flags |= IFF_OACTIVE;
+ return;
+ }
+ for (;;) {
IFQ_DRV_DEQUEUE(&ifp->if_snd, m); /* XXX: LOCK */
if (m == NULL)
break;
@@ -467,8 +473,10 @@
/* NB: power management bit is never sent by an AP */
if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) &&
vap->iv_opmode != IEEE80211_M_HOSTAP &&
- vap->iv_opmode != IEEE80211_M_WDS)
+ vap->iv_opmode != IEEE80211_M_WDS) {
wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT;
+ m->m_flags |= M_PWR_DOWN; /* force special handling */
+ }
/* XXX WDS? */
m->m_len = m->m_pkthdr.len = sizeof(struct ieee80211_frame);
==== //depot/projects/vap/sys/net80211/ieee80211_power.c#3 (text+ko) ====
@@ -276,33 +276,33 @@
/*
* Flush queued unicast frames.
*/
- if (IEEE80211_NODE_SAVEQ_QLEN(ni) == 0) {
- if (vap->iv_set_tim != NULL)
- vap->iv_set_tim(ni, 0); /* just in case */
- return;
- }
- IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
- "flush ps queue, %u packets queued", IEEE80211_NODE_SAVEQ_QLEN(ni));
- for (;;) {
- int qlen;
+ if (IEEE80211_NODE_SAVEQ_QLEN(ni) != 0) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
+ "flush ps queue, %u packets queued",
+ IEEE80211_NODE_SAVEQ_QLEN(ni));
+ for (;;) {
+ int qlen;
- IEEE80211_NODE_SAVEQ_DEQUEUE(ni, m, qlen);
- if (m == NULL)
- break;
- /*
- * If this is the last packet, turn off the TIM bit.
- * If there are more packets, set the more packets bit
- * in the packet dispatched to the station.
- */
- if (qlen != 0) {
- struct ieee80211_frame_min *wh =
- mtod(m, struct ieee80211_frame_min *);
- wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
+ IEEE80211_NODE_SAVEQ_DEQUEUE(ni, m, qlen);
+ if (m == NULL)
+ break;
+ /*
+ * If this is the last packet, turn off the TIM bit.
+ * If there are more packets, set the more packets bit
+ * in the packet dispatched to the station.
+ */
+ if (qlen != 0) {
+ struct ieee80211_frame_min *wh =
+ mtod(m, struct ieee80211_frame_min *);
+ wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
+ }
+ /* XXX need different driver interface */
+ /* XXX bypasses q max */
+ IF_ENQUEUE(&vap->iv_arp.ac_if.if_snd, m);
}
- /* XXX need different driver interface */
- /* XXX bypasses q max */
- IF_ENQUEUE(&vap->iv_arp.ac_if.if_snd, m);
}
+ if (vap->iv_set_tim != NULL)
+ vap->iv_set_tim(ni, 0);
}
/*
@@ -362,3 +362,21 @@
ieee80211_send_nulldata(ieee80211_ref_node(ni));
}
}
+
+void
+ieee80211_power_poll(struct ieee80211com *ic)
+{
+ if (ic->ic_opmode == IEEE80211_M_STA &&
+ (ic->ic_flags & IEEE80211_F_PMGTON) &&
+ ic->ic_nrunning &&
+ (ticks - ic->ic_lastdata) > ic->ic_lintval) {
+ struct ieee80211vap *vap;
+
+ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
+ if (vap->iv_opmode == IEEE80211_M_STA &&
+ vap->iv_state == IEEE80211_S_RUN) {
+ ieee80211_new_state(vap, IEEE80211_S_SLEEP, 0);
+ break;
+ }
+ }
+}
==== //depot/projects/vap/sys/net80211/ieee80211_power.h#2 (text+ko) ====
@@ -47,4 +47,6 @@
void ieee80211_pwrsave(struct ieee80211_node *, struct mbuf *);
void ieee80211_node_pwrsave(struct ieee80211_node *, int enable);
void ieee80211_sta_pwrsave(struct ieee80211vap *, int enable);
+
+void ieee80211_power_poll(struct ieee80211com *);
#endif /* _NET80211_IEEE80211_POWER_H_ */
==== //depot/projects/vap/sys/net80211/ieee80211_proto.c#12 (text+ko) ====
@@ -76,7 +76,8 @@
"SCAN", /* IEEE80211_S_SCAN */
"AUTH", /* IEEE80211_S_AUTH */
"ASSOC", /* IEEE80211_S_ASSOC */
- "RUN" /* IEEE80211_S_RUN */
+ "RUN", /* IEEE80211_S_RUN */
+ "SLEEP" /* IEEE80211_S_SLEEP */
};
const char *ieee80211_wme_acnames[] = {
"WME_AC_BE",
@@ -958,7 +959,7 @@
* simply by re-associating. Otherwise we need to
* re-scan to select an appropriate ap.
*/
- if (vap->iv_state != IEEE80211_S_RUN || forcescan)
+ if (vap->iv_state < IEEE80211_S_RUN || forcescan)
ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
else
ieee80211_new_state(vap, IEEE80211_S_ASSOC, 1);
@@ -1109,7 +1110,7 @@
* through different means (e.g. the tx timeout on mgt frames).
*/
if (vap->iv_opmode != IEEE80211_M_STA ||
- vap->iv_state != IEEE80211_S_RUN)
+ vap->iv_state < IEEE80211_S_RUN)
continue;
if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) {
/*
@@ -1136,12 +1137,33 @@
}
}
+static void
+sta_disassoc(void *arg, struct ieee80211_node *ni)
+{
+ struct ieee80211vap *vap = arg;
+
+ if (ni->ni_vap == vap && ni->ni_associd != 0) {
+ IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DISASSOC,
+ IEEE80211_REASON_ASSOC_LEAVE);
+ ieee80211_node_leave(ni);
+ }
+}
+
+static void
+sta_deauth(void *arg, struct ieee80211_node *ni)
+{
+ struct ieee80211vap *vap = arg;
+
+ if (ni->ni_vap == vap)
+ IEEE80211_SEND_MGMT(ni, IEEE80211_FC0_SUBTYPE_DEAUTH,
+ IEEE80211_REASON_ASSOC_LEAVE);
+}
+
static int
ieee80211_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
{
struct ieee80211com *ic = vap->iv_ic;
struct ifnet *ifp = &vap->iv_if;
- struct ieee80211_node_table *nt;
struct ieee80211_node *ni;
enum ieee80211_state ostate;
@@ -1159,6 +1181,7 @@
switch (ostate) {
case IEEE80211_S_INIT:
break;
+ case IEEE80211_S_SLEEP:
case IEEE80211_S_RUN:
switch (vap->iv_opmode) {
case IEEE80211_M_STA:
@@ -1168,17 +1191,8 @@
ieee80211_sta_leave(ni);
break;
case IEEE80211_M_HOSTAP:
- nt = &ic->ic_sta;
- IEEE80211_NODE_LOCK(nt);
- TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
- if (ni->ni_associd == 0 ||
- ni->ni_vap != vap)
- continue;
- IEEE80211_SEND_MGMT(ni,
- IEEE80211_FC0_SUBTYPE_DISASSOC,
- IEEE80211_REASON_ASSOC_LEAVE);
- }
- IEEE80211_NODE_UNLOCK(nt);
+ ieee80211_iterate_nodes(&ic->ic_sta,
+ sta_disassoc, vap);
break;
default:
break;
@@ -1192,16 +1206,8 @@
IEEE80211_REASON_AUTH_LEAVE);
break;
case IEEE80211_M_HOSTAP:
- nt = &ic->ic_sta;
- IEEE80211_NODE_LOCK(nt);
- TAILQ_FOREACH(ni, &nt->nt_node, ni_list) {
- if (ni->ni_vap != vap)
- continue;
- IEEE80211_SEND_MGMT(ni,
- IEEE80211_FC0_SUBTYPE_DEAUTH,
- IEEE80211_REASON_AUTH_LEAVE);
- }
- IEEE80211_NODE_UNLOCK(nt);
+ ieee80211_iterate_nodes(&ic->ic_sta,
+ sta_deauth, vap);
break;
default:
break;
@@ -1251,6 +1257,7 @@
}
break;
case IEEE80211_S_RUN: /* beacon miss */
+ case IEEE80211_S_SLEEP:
ieee80211_sta_leave(ni);
vap->iv_flags &= ~IEEE80211_F_SIBSS; /* XXX */
if (ic->ic_roaming == IEEE80211_ROAMING_AUTO)
@@ -1283,6 +1290,7 @@
}
break;
case IEEE80211_S_RUN:
+ case IEEE80211_S_SLEEP:
switch (arg) {
case IEEE80211_FC0_SUBTYPE_AUTH:
IEEE80211_SEND_MGMT(ni,
@@ -1317,6 +1325,7 @@
IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
break;
case IEEE80211_S_RUN:
+ case IEEE80211_S_SLEEP:
ieee80211_sta_leave(ni);
if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) {
/* NB: caller specifies ASSOC/REASSOC by arg */
@@ -1349,8 +1358,6 @@
IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY,
"%s: invalid transition\n", __func__);
break;
- case IEEE80211_S_RUN:
- break;
case IEEE80211_S_SCAN: /* adhoc/hostap mode */
case IEEE80211_S_ASSOC: /* infra mode */
KASSERT(ni->ni_txrate < ni->ni_rates.rs_nrates,
@@ -1373,6 +1380,11 @@
ieee80211_notify_node_join(ni,
arg == IEEE80211_FC0_SUBTYPE_ASSOC_RESP);
break;
+ case IEEE80211_S_RUN:
+ break;
+ case IEEE80211_S_SLEEP:
+ ieee80211_sta_pwrsave(vap, 0);
+ return 0;
}
/*
* Start/stop the authenticator when operating as an
@@ -1396,6 +1408,12 @@
if_start(ifp);
}
break;
+ case IEEE80211_S_SLEEP:
+ KASSERT(vap->iv_opmode == IEEE80211_M_STA,
+ ("switch to %s state when operating in mode %u",
+ ieee80211_state_name[nstate], vap->iv_opmode));
+ ieee80211_sta_pwrsave(vap, 1);
+ break;
}
return 0;
}
==== //depot/projects/vap/sys/net80211/ieee80211_proto.h#7 (text+ko) ====
@@ -44,8 +44,9 @@
IEEE80211_S_AUTH = 2, /* try to authenticate */
IEEE80211_S_ASSOC = 3, /* try to assoc */
IEEE80211_S_RUN = 4, /* associated */
+ IEEE80211_S_SLEEP = 5, /* power save */
};
-#define IEEE80211_S_MAX (IEEE80211_S_RUN+1)
+#define IEEE80211_S_MAX (IEEE80211_S_SLEEP+1)
#define IEEE80211_SEND_MGMT(_ni,_type,_arg) \
((*(_ni)->ni_ic->ic_send_mgmt)(_ni, _type, _arg))
More information about the p4-projects
mailing list