summaryrefslogtreecommitdiff
path: root/sys/net80211
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net80211')
-rw-r--r--sys/net80211/ieee80211_input.c10
-rw-r--r--sys/net80211/ieee80211_output.c75
-rw-r--r--sys/net80211/ieee80211_proto.h6
-rw-r--r--sys/net80211/ieee80211_var.h4
4 files changed, 66 insertions, 29 deletions
diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c
index dc5808885a9..a98174527c0 100644
--- a/sys/net80211/ieee80211_input.c
+++ b/sys/net80211/ieee80211_input.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_input.c,v 1.103 2008/08/29 12:14:53 damien Exp $ */
+/* $OpenBSD: ieee80211_input.c,v 1.104 2008/09/01 19:41:10 damien Exp $ */
/*-
* Copyright (c) 2001 Atsushi Onoe
@@ -215,8 +215,8 @@ ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
}
#ifndef IEEE80211_STA_ONLY
- if ((ic->ic_caps & IEEE80211_C_PMGT) &&
- ic->ic_opmode == IEEE80211_M_HOSTAP &&
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
+ (ic->ic_caps & IEEE80211_C_APPMGT) &&
ni->ni_state == IEEE80211_STA_ASSOC) {
if (wh->i_fc[1] & IEEE80211_FC1_PWR_MGT) {
if (ni->ni_pwrsave == IEEE80211_PS_AWAKE) {
@@ -1998,8 +1998,8 @@ ieee80211_recv_pspoll(struct ieee80211com *ic, struct mbuf *m,
struct ieee80211_frame *wh;
u_int16_t aid;
- if (!(ic->ic_caps & IEEE80211_C_PMGT) ||
- ic->ic_opmode != IEEE80211_M_HOSTAP ||
+ if (ic->ic_opmode != IEEE80211_M_HOSTAP ||
+ !(ic->ic_caps & IEEE80211_C_APPMGT) ||
ni->ni_state != IEEE80211_STA_ASSOC)
return;
diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c
index cb4181759c5..da7d2f1a953 100644
--- a/sys/net80211/ieee80211_output.c
+++ b/sys/net80211/ieee80211_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_output.c,v 1.73 2008/08/29 12:14:53 damien Exp $ */
+/* $OpenBSD: ieee80211_output.c,v 1.74 2008/09/01 19:41:10 damien Exp $ */
/* $NetBSD: ieee80211_output.c,v 1.13 2004/05/31 11:02:55 dyoung Exp $ */
/*-
@@ -238,6 +238,11 @@ ieee80211_mgmt_output(struct ifnet *ifp, struct ieee80211_node *ni,
ieee80211_chan2mode(ic, ni->ni_chan)]);
}
+#ifndef IEEE80211_STA_ONLY
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
+ ieee80211_pwrsave(ic, m, ni) != 0)
+ return 0;
+#endif
IF_ENQUEUE(&ic->ic_mgtq, m);
ifp->if_timer = 1;
(*ifp->if_start)(ifp);
@@ -606,6 +611,13 @@ ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni)
(ni->ni_flags & IEEE80211_NODE_TXPROT)))
wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
+#ifndef IEEE80211_STA_ONLY
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP &&
+ ieee80211_pwrsave(ic, m, ni) != 0) {
+ *pni = NULL;
+ return NULL;
+ }
+#endif
*pni = ni;
return m;
bad:
@@ -718,7 +730,7 @@ ieee80211_add_tim(u_int8_t *frm, struct ieee80211com *ic)
/* Bitmap Control */
*frm = offset;
/* set broadcast/multicast indication bit if necessary */
- if (ic->ic_dtim_count == 0 && ic->ic_tim_mcast)
+ if (ic->ic_dtim_count == 0 && ic->ic_tim_mcast_pending)
*frm |= 0x01;
frm++;
@@ -1527,31 +1539,56 @@ ieee80211_beacon_alloc(struct ieee80211com *ic, struct ieee80211_node *ni)
return m;
}
-void
-ieee80211_pwrsave(struct ieee80211com *ic, struct ieee80211_node *ni,
- struct mbuf *m)
+/*
+ * Check if an outgoing MSDU or management frame should be buffered into
+ * the AP for power management. Return 1 if the frame was buffered into
+ * the AP, or 0 if the frame shall be transmitted immediately.
+ */
+int
+ieee80211_pwrsave(struct ieee80211com *ic, struct mbuf *m,
+ struct ieee80211_node *ni)
{
- /* store the new packet on our queue, changing the TIM if necessary */
- if (IF_IS_EMPTY(&ni->ni_savedq))
- (*ic->ic_set_tim)(ic, ni->ni_associd, 1);
+ const struct ieee80211_frame *wh;
- if (ni->ni_savedq.ifq_len >= IEEE80211_PS_MAX_QUEUE) {
+ KASSERT(ic->ic_opmode == IEEE80211_M_HOSTAP);
+ if (!(ic->ic_caps & IEEE80211_C_APPMGT))
+ return 0;
+
+ wh = mtod(m, struct ieee80211_frame *);
+ if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+ /*
+ * Buffer group addressed MSDUs with the Order bit clear
+ * if any associated STAs are in PS mode.
+ */
+ if ((wh->i_fc[1] & IEEE80211_FC1_ORDER) ||
+ ic->ic_pssta == 0)
+ return 0;
+ ic->ic_tim_mcast_pending = 1;
+ } else {
+ /*
+ * Buffer MSDUs, A-MSDUs or management frames destined for
+ * PS STAs.
+ */
+ if (ni->ni_pwrsave == IEEE80211_PS_AWAKE ||
+ (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
+ IEEE80211_FC0_TYPE_CTL)
+ return 0;
+ if (IF_IS_EMPTY(&ni->ni_savedq))
+ (*ic->ic_set_tim)(ic, ni->ni_associd, 1);
+ }
+ /* NB: ni == ic->ic_bss for broadcast/multicast */
+ if (IF_QFULL(&ni->ni_savedq)) {
+ /* XXX should we drop the oldest instead? */
IF_DROP(&ni->ni_savedq);
m_freem(m);
- if (ic->ic_if.if_flags & IFF_DEBUG)
- printf("%s: station %s power save queue overflow"
- " of size %d drops %d\n",
- ic->ic_if.if_xname,
- ether_sprintf(ni->ni_macaddr),
- IEEE80211_PS_MAX_QUEUE,
- ni->ni_savedq.ifq_drops);
} else {
+ IF_ENQUEUE(&ni->ni_savedq, m);
/*
- * Similar to ieee80211_mgmt_output, store the node in
- * the rcvif field.
+ * Similar to ieee80211_mgmt_output, store the node in the
+ * rcvif field.
*/
- IF_ENQUEUE(&ni->ni_savedq, m);
m->m_pkthdr.rcvif = (void *)ni;
}
+ return 1;
}
#endif /* IEEE80211_STA_ONLY */
diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h
index 93982eec369..15b316c4efa 100644
--- a/sys/net80211/ieee80211_proto.h
+++ b/sys/net80211/ieee80211_proto.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_proto.h,v 1.33 2008/08/14 15:51:43 damien Exp $ */
+/* $OpenBSD: ieee80211_proto.h,v 1.34 2008/09/01 19:41:10 damien Exp $ */
/* $NetBSD: ieee80211_proto.h,v 1.3 2003/10/13 04:23:56 dyoung Exp $ */
/*-
@@ -95,8 +95,8 @@ extern int ieee80211_send_group_msg2(struct ieee80211com *,
struct ieee80211_node *, const struct ieee80211_key *);
extern int ieee80211_send_eapol_key_req(struct ieee80211com *,
struct ieee80211_node *, u_int16_t, u_int64_t);
-extern void ieee80211_pwrsave(struct ieee80211com *, struct ieee80211_node *,
- struct mbuf *);
+extern int ieee80211_pwrsave(struct ieee80211com *, struct mbuf *,
+ struct ieee80211_node *);
extern struct mbuf *ieee80211_decap(struct ifnet *, struct mbuf *, int);
#define ieee80211_new_state(_ic, _nstate, _arg) \
(((_ic)->ic_newstate)((_ic), (_nstate), (_arg)))
diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h
index 568a76350b2..f327032d5e9 100644
--- a/sys/net80211/ieee80211_var.h
+++ b/sys/net80211/ieee80211_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ieee80211_var.h,v 1.50 2008/08/29 12:14:53 damien Exp $ */
+/* $OpenBSD: ieee80211_var.h,v 1.51 2008/09/01 19:41:11 damien Exp $ */
/* $NetBSD: ieee80211_var.h,v 1.7 2004/05/06 03:07:10 dyoung Exp $ */
/*-
@@ -291,7 +291,7 @@ struct ieee80211com {
u_int8_t *ic_tim_bitmap;
u_int ic_tim_len;
- u_int ic_tim_mcast;
+ u_int ic_tim_mcast_pending;
u_int ic_dtim_period;
u_int ic_dtim_count;
};