summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2015-05-12 16:55:50 +0000
committeradrian <adrian@FreeBSD.org>2015-05-12 16:55:50 +0000
commit7ce4eee72071905de1b261a8009c2fea01df2e36 (patch)
tree716461345caf036699974e8086adfb6b3ba88e3a
parentb9ba488f00f4863fd988318bd429fa3768e59917 (diff)
downloadFreeBSD-src-7ce4eee72071905de1b261a8009c2fea01df2e36.zip
FreeBSD-src-7ce4eee72071905de1b261a8009c2fea01df2e36.tar.gz
Do not check sequence number for QoS Null frames; set it for generated QoS Null
frames to 0 From IEEE Std. 802.11-2012, 8.3.2.1 "Data frame format", p. 415 (513): "The Sequence Control field for QoS (+)Null frames is ignored by the receiver upon reception." At this moment, any <mode>_input() function interprets them as regular QoS data frames with TID = 0. As a result, stations, that use another TX sequence for QoS Null frames (e.g. wpi(4), where (QoS) Null frames are generated by the firmware), may experience significant packet loss with any other NIC in hostap mode. Tested: * wpi(4) (author) * iwn(4) - Intel 5100, STA mode (me) PR: kern/200128 Submitted by: Andriy Voskoboinyk <s3erios@gmail.com>
-rw-r--r--sys/net80211/ieee80211.h5
-rw-r--r--sys/net80211/ieee80211_adhoc.c4
-rw-r--r--sys/net80211/ieee80211_hostap.c3
-rw-r--r--sys/net80211/ieee80211_input.h12
-rw-r--r--sys/net80211/ieee80211_output.c7
-rw-r--r--sys/net80211/ieee80211_sta.c4
-rw-r--r--sys/net80211/ieee80211_wds.c3
7 files changed, 24 insertions, 14 deletions
diff --git a/sys/net80211/ieee80211.h b/sys/net80211/ieee80211.h
index 9b005f3..8e586bd 100644
--- a/sys/net80211/ieee80211.h
+++ b/sys/net80211/ieee80211.h
@@ -169,6 +169,11 @@ struct ieee80211_qosframe_addr4 {
#define IEEE80211_FC1_PROTECTED 0x40
#define IEEE80211_FC1_ORDER 0x80
+#define IEEE80211_HAS_SEQ(type, subtype) \
+ ((type) != IEEE80211_FC0_TYPE_CTL && \
+ !((type) == IEEE80211_FC0_TYPE_DATA && \
+ ((subtype) & IEEE80211_FC0_SUBTYPE_QOS_NULL) == \
+ IEEE80211_FC0_SUBTYPE_QOS_NULL))
#define IEEE80211_SEQ_FRAG_MASK 0x000f
#define IEEE80211_SEQ_FRAG_SHIFT 0
#define IEEE80211_SEQ_SEQ_MASK 0xfff0
diff --git a/sys/net80211/ieee80211_adhoc.c b/sys/net80211/ieee80211_adhoc.c
index a3d4e51..0d761c4 100644
--- a/sys/net80211/ieee80211_adhoc.c
+++ b/sys/net80211/ieee80211_adhoc.c
@@ -291,7 +291,6 @@ doprint(struct ieee80211vap *vap, int subtype)
static int
adhoc_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
{
-#define HAS_SEQ(type) ((type & 0x4) == 0)
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
struct ifnet *ifp = vap->iv_ifp;
@@ -414,7 +413,8 @@ adhoc_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
}
IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
ni->ni_noise = nf;
- if (HAS_SEQ(type) && IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr)) {
+ if (IEEE80211_HAS_SEQ(type, subtype) &&
+ IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr)) {
uint8_t tid = ieee80211_gettid(wh);
if (IEEE80211_QOS_HAS_SEQ(wh) &&
TID_TO_WME_AC(tid) >= WME_AC_VI)
diff --git a/sys/net80211/ieee80211_hostap.c b/sys/net80211/ieee80211_hostap.c
index 8c7b8f5..a625b4e 100644
--- a/sys/net80211/ieee80211_hostap.c
+++ b/sys/net80211/ieee80211_hostap.c
@@ -478,7 +478,6 @@ doprint(struct ieee80211vap *vap, int subtype)
static int
hostap_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
{
-#define HAS_SEQ(type) ((type & 0x4) == 0)
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
struct ifnet *ifp = vap->iv_ifp;
@@ -571,7 +570,7 @@ hostap_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
ni->ni_noise = nf;
- if (HAS_SEQ(type)) {
+ if (IEEE80211_HAS_SEQ(type, subtype)) {
uint8_t tid = ieee80211_gettid(wh);
if (IEEE80211_QOS_HAS_SEQ(wh) &&
TID_TO_WME_AC(tid) >= WME_AC_VI)
diff --git a/sys/net80211/ieee80211_input.h b/sys/net80211/ieee80211_input.h
index b90f46a..f3d569e 100644
--- a/sys/net80211/ieee80211_input.h
+++ b/sys/net80211/ieee80211_input.h
@@ -168,19 +168,22 @@ ieee80211_check_rxseq(struct ieee80211_node *ni, struct ieee80211_frame *wh)
{
#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0)
#define SEQ_EQ(a,b) ((int)((a)-(b)) == 0)
-#define HAS_SEQ(type) ((type & 0x4) == 0)
#define SEQNO(a) ((a) >> IEEE80211_SEQ_SEQ_SHIFT)
#define FRAGNO(a) ((a) & IEEE80211_SEQ_FRAG_MASK)
uint16_t rxseq;
- uint8_t type;
+ uint8_t type, subtype;
uint8_t tid;
struct ieee80211_rx_ampdu *rap;
rxseq = le16toh(*(uint16_t *)wh->i_seq);
type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+ subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
- /* Types with no sequence number are always treated valid */
- if (! HAS_SEQ(type))
+ /*
+ * Types with no sequence number (or QoS (+)Null frames)
+ * are always treated valid.
+ */
+ if (! IEEE80211_HAS_SEQ(type, subtype))
return 1;
tid = ieee80211_gettid(wh);
@@ -235,7 +238,6 @@ ieee80211_check_rxseq(struct ieee80211_node *ni, struct ieee80211_frame *wh)
return 1;
#undef SEQ_LEQ
#undef SEQ_EQ
-#undef HAS_SEQ
#undef SEQNO
#undef FRAGNO
}
diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c
index 5647c03..d141cf3 100644
--- a/sys/net80211/ieee80211_output.c
+++ b/sys/net80211/ieee80211_output.c
@@ -730,7 +730,12 @@ ieee80211_send_setup(
if (tid != IEEE80211_NONQOS_TID && IEEE80211_AMPDU_RUNNING(tap))
m->m_flags |= M_AMPDU_MPDU;
else {
- seqno = ni->ni_txseqs[tid]++;
+ if (IEEE80211_HAS_SEQ(type & IEEE80211_FC0_TYPE_MASK,
+ type & IEEE80211_FC0_SUBTYPE_MASK))
+ seqno = ni->ni_txseqs[tid]++;
+ else
+ seqno = 0;
+
*(uint16_t *)&wh->i_seq[0] =
htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
M_SEQNO_SET(m, seqno);
diff --git a/sys/net80211/ieee80211_sta.c b/sys/net80211/ieee80211_sta.c
index 5a21747..267ad11 100644
--- a/sys/net80211/ieee80211_sta.c
+++ b/sys/net80211/ieee80211_sta.c
@@ -527,7 +527,6 @@ doprint(struct ieee80211vap *vap, int subtype)
static int
sta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
{
-#define HAS_SEQ(type) ((type & 0x4) == 0)
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
struct ifnet *ifp = vap->iv_ifp;
@@ -623,7 +622,8 @@ sta_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
ni->ni_noise = nf;
- if (HAS_SEQ(type) && !IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+ if ( IEEE80211_HAS_SEQ(type, subtype) &&
+ !IEEE80211_IS_MULTICAST(wh->i_addr1)) {
uint8_t tid = ieee80211_gettid(wh);
if (IEEE80211_QOS_HAS_SEQ(wh) &&
TID_TO_WME_AC(tid) >= WME_AC_VI)
diff --git a/sys/net80211/ieee80211_wds.c b/sys/net80211/ieee80211_wds.c
index ec1bd85..9e46bf1 100644
--- a/sys/net80211/ieee80211_wds.c
+++ b/sys/net80211/ieee80211_wds.c
@@ -406,7 +406,6 @@ wds_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
static int
wds_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
{
-#define HAS_SEQ(type) ((type & 0x4) == 0)
struct ieee80211vap *vap = ni->ni_vap;
struct ieee80211com *ic = ni->ni_ic;
struct ifnet *ifp = vap->iv_ifp;
@@ -488,7 +487,7 @@ wds_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
}
IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi);
ni->ni_noise = nf;
- if (HAS_SEQ(type)) {
+ if (IEEE80211_HAS_SEQ(type, subtype)) {
uint8_t tid = ieee80211_gettid(wh);
if (IEEE80211_QOS_HAS_SEQ(wh) &&
TID_TO_WME_AC(tid) >= WME_AC_VI)
OpenPOWER on IntegriCloud