Index: head/sys/net80211/ieee80211_ht.c =================================================================== --- head/sys/net80211/ieee80211_ht.c +++ head/sys/net80211/ieee80211_ht.c @@ -827,6 +827,16 @@ */ return PROCESS; } + + /* + * 802.11-2012 9.3.2.10 - Duplicate detection and recovery. + * + * Multicast QoS data frames are checked against a different + * counter, not the per-TID counter. + */ + if (IEEE80211_IS_MULTICAST(wh->i_addr1)) + return PROCESS; + if (IEEE80211_IS_DSTODS(wh)) tid = ((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0]; else Index: head/sys/net80211/ieee80211_input.h =================================================================== --- head/sys/net80211/ieee80211_input.h +++ head/sys/net80211/ieee80211_input.h @@ -149,6 +149,12 @@ * (as the seqnum wraps), handle that special case so packets aren't * incorrectly dropped - ie, if the next packet is sequence number 0 * but a retransmit since the initial packet didn't make it. + * + * XXX TODO: handle sequence number space wrapping with dropped frames; + * especially in high interference conditions under high traffic load + * The RX AMPDU reorder code also needs it. + * + * XXX TODO: update for 802.11-2012 9.3.2.10 Duplicate Detection and Recovery. */ static __inline int ieee80211_check_rxseq(struct ieee80211_node *ni, struct ieee80211_frame *wh, @@ -175,6 +181,13 @@ if (! IEEE80211_HAS_SEQ(type, subtype)) return 1; + /* + * Always allow multicast frames for now - QoS (any TID) + * or not. + */ + if (IEEE80211_IS_MULTICAST(wh->i_addr1)) + return 1; + tid = ieee80211_gettid(wh); /* Index: head/sys/net80211/ieee80211_output.c =================================================================== --- head/sys/net80211/ieee80211_output.c +++ head/sys/net80211/ieee80211_output.c @@ -122,9 +122,7 @@ { struct ieee80211com *ic = vap->iv_ic; struct ifnet *ifp = vap->iv_ifp; -#ifdef IEEE80211_SUPPORT_SUPERG int mcast; -#endif if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && (m->m_flags & M_PWR_SAV) == 0) { @@ -164,9 +162,7 @@ * interface it (might have been) received on. */ m->m_pkthdr.rcvif = (void *)ni; -#ifdef IEEE80211_SUPPORT_SUPERG mcast = (m->m_flags & (M_MCAST | M_BCAST)) ? 1: 0; -#endif BPF_MTAP(ifp, m); /* 802.3 tx */ @@ -181,10 +177,15 @@ * The default ic_ampdu_enable routine handles staggering * ADDBA requests in case the receiver NAK's us or we are * otherwise unable to establish a BA stream. + * + * Don't treat group-addressed frames as candidates for aggregation; + * net80211 doesn't support 802.11aa-2012 and so group addressed + * frames will always have sequence numbers allocated from the NON_QOS + * TID. */ if ((ni->ni_flags & IEEE80211_NODE_AMPDU_TX) && (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_TX)) { - if ((m->m_flags & M_EAPOL) == 0) { + if ((m->m_flags & M_EAPOL) == 0 && (! mcast)) { int tid = WME_AC_TO_TID(M_WME_GETAC(m)); struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[tid]; @@ -776,12 +777,20 @@ * requiring the TX lock. */ tap = &ni->ni_tx_ampdu[tid]; - if (tid != IEEE80211_NONQOS_TID && IEEE80211_AMPDU_RUNNING(tap)) + if (tid != IEEE80211_NONQOS_TID && IEEE80211_AMPDU_RUNNING(tap)) { m->m_flags |= M_AMPDU_MPDU; - else { + } else { if (IEEE80211_HAS_SEQ(type & IEEE80211_FC0_TYPE_MASK, type & IEEE80211_FC0_SUBTYPE_MASK)) - seqno = ni->ni_txseqs[tid]++; + /* + * 802.11-2012 9.3.2.10 - QoS multicast frames + * come out of a different seqno space. + */ + if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { + seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; + } else { + seqno = ni->ni_txseqs[tid]++; + } else seqno = 0; @@ -1239,7 +1248,7 @@ struct ieee80211_frame *wh; struct ieee80211_key *key; struct llc *llc; - int hdrsize, hdrspace, datalen, addqos, txfrag, is4addr; + int hdrsize, hdrspace, datalen, addqos, txfrag, is4addr, is_mcast; ieee80211_seq seqno; int meshhdrsize, meshae; uint8_t *qos; @@ -1247,6 +1256,8 @@ IEEE80211_TX_LOCK_ASSERT(ic); + is_mcast = !! (m->m_flags & (M_MCAST | M_BCAST)); + /* * Copy existing Ethernet header to a safe place. The * rest of the code assumes it's ok to strip it when @@ -1291,11 +1302,19 @@ * ap's require all data frames to be QoS-encapsulated * once negotiated in which case we'll need to make this * configurable. - * NB: mesh data frames are QoS. + * + * Don't send multicast QoS frames. + * Technically multicast frames can be QoS if all stations in the + * BSS are also QoS. + * + * NB: mesh data frames are QoS, including multicast frames. */ - addqos = ((ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) || + addqos = + (((is_mcast == 0) && (ni->ni_flags & + (IEEE80211_NODE_QOS|IEEE80211_NODE_HT))) || (vap->iv_opmode == IEEE80211_M_MBSS)) && (m->m_flags & M_EAPOL) == 0; + if (addqos) hdrsize = sizeof(struct ieee80211_qosframe); else @@ -1560,6 +1579,22 @@ */ if ((m->m_flags & M_AMPDU_MPDU) == 0) { /* + * 802.11-2012 9.3.2.10 - + * + * If this is a multicast frame then we need + * to ensure that the sequence number comes from + * a separate seqno space and not the TID space. + * + * Otherwise multicast frames may actually cause + * holes in the TX blockack window space and + * upset various things. + */ + if (IEEE80211_IS_MULTICAST(wh->i_addr1)) + seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; + else + seqno = ni->ni_txseqs[tid]++; + + /* * NB: don't assign a sequence # to potential * aggregates; we expect this happens at the * point the frame comes off any aggregation q