-/* $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
}
#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) {
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;
-/* $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 $ */
/*-
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);
(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:
/* 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++;
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 */
-/* $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 $ */
/*-
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)))