* Introduce new flag for QoS control field;

* Change in mesh_input to validate that QoS is set and Mesh Control field
  is present, also both bytes of the QoS are read;
* Moved defragmentation in mesh_input before we try to forward packet as
  inferred from amendment spec, because Mesh Control field only present in first
  fragment;
* Changed in ieee80211_encap to set QoS subtype and Mesh Control field present,
  only first fragment have Mesh Control field present bit equal to 1;

Submitted by:	monthadar@gmail.com
This commit is contained in:
Adrian Chadd 2012-03-04 05:52:26 +00:00
parent bdd2a07668
commit 91216c714c
3 changed files with 88 additions and 28 deletions

View File

@ -199,6 +199,13 @@ struct ieee80211_qosframe_addr4 {
#define IEEE80211_QOS_EOSP 0x10 /* EndOfService Period*/
#define IEEE80211_QOS_EOSP_S 4
#define IEEE80211_QOS_TID 0x0f
/* qos[1] byte used for all frames sent by mesh STAs in a mesh BSS */
#define IEEE80211_QOS_MC 0x10 /* Mesh control */
/* Mesh power save level*/
#define IEEE80211_QOS_MESH_PSL 0x20
/* Mesh Receiver Service Period Initiated */
#define IEEE80211_QOS_RSPI 0x40
/* bits 11 to 15 reserved */
/* does frame have QoS sequence control data */
#define IEEE80211_QOS_HAS_SEQ(wh) \

View File

@ -1040,9 +1040,9 @@ mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
struct ieee80211_frame *wh;
const struct ieee80211_meshcntl *mc;
int hdrspace, meshdrlen, need_tap;
uint8_t dir, type, subtype, qos;
uint8_t dir, type, subtype;
uint32_t seq;
uint8_t *addr;
uint8_t *addr, qos[2];
ieee80211_seq rxseq;
KASSERT(ni != NULL, ("null node"));
@ -1139,8 +1139,64 @@ mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
vap->iv_stats.is_rx_wrongdir++;
goto err;
}
/* pull up enough to get to the mesh control */
/* All Mesh data frames are QoS subtype */
if (!HAS_SEQ(type)) {
IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
wh, "data", "incorrect subtype 0x%x", subtype);
vap->iv_stats.is_rx_badsubtype++;
goto err;
}
/*
* Next up, any fragmentation.
* XXX: we defrag before we even try to forward,
* Mesh Control field is not present in sub-sequent
* fragmented frames. This is in contrast to Draft 4.0.
*/
hdrspace = ieee80211_hdrspace(ic, wh);
if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
m = ieee80211_defrag(ni, m, hdrspace);
if (m == NULL) {
/* Fragment dropped or frame not complete yet */
goto out;
}
}
wh = mtod(m, struct ieee80211_frame *); /* NB: after defrag */
/*
* Now we have a complete Mesh Data frame.
*/
/*
* Only fromDStoDS data frames use 4 address qos frames
* as specified in amendment. Otherwise addr4 is located
* in the Mesh Control field and a 3 address qos frame
* is used.
*/
if (IEEE80211_IS_DSTODS(wh))
*(uint16_t *)qos = *(uint16_t *)
((struct ieee80211_qosframe_addr4 *)wh)->i_qos;
else
*(uint16_t *)qos = *(uint16_t *)
((struct ieee80211_qosframe *)wh)->i_qos;
/*
* NB: The mesh STA sets the Mesh Control Present
* subfield to 1 in the Mesh Data frame containing
* an unfragmented MSDU, an A-MSDU, or the first
* fragment of an MSDU.
* After defrag it should always be present.
*/
if (!(qos[1] & IEEE80211_QOS_MC)) {
IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_MESH,
ni->ni_macaddr, NULL,
"%s", "Mesh control field not present");
vap->iv_stats.is_rx_elem_missing++; /* XXX: kinda */
goto err;
}
/* pull up enough to get to the mesh control */
if (m->m_len < hdrspace + sizeof(struct ieee80211_meshcntl) &&
(m = m_pullup(m, hdrspace +
sizeof(struct ieee80211_meshcntl))) == NULL) {
@ -1188,27 +1244,6 @@ mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
/* NB: fall thru to deliver mcast frames locally */
}
/*
* Save QoS bits for use below--before we strip the header.
*/
if (subtype == IEEE80211_FC0_SUBTYPE_QOS) {
qos = (dir == IEEE80211_FC1_DIR_DSTODS) ?
((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0] :
((struct ieee80211_qosframe *)wh)->i_qos[0];
} else
qos = 0;
/*
* Next up, any fragmentation.
*/
if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
m = ieee80211_defrag(ni, m, hdrspace);
if (m == NULL) {
/* Fragment dropped or frame not complete yet */
goto out;
}
}
wh = NULL; /* no longer valid, catch any uses */
if (ieee80211_radiotap_active_vap(vap))
ieee80211_radiotap_rx(vap, m);
need_tap = 0;
@ -1229,7 +1264,7 @@ mesh_input(struct ieee80211_node *ni, struct mbuf *m, int rssi, int nf)
IEEE80211_NODE_STAT(ni, rx_decap);
goto err;
}
if (qos & IEEE80211_QOS_AMSDU) {
if (qos[0] & IEEE80211_QOS_AMSDU) {
m = ieee80211_decap_amsdu(ni, m);
if (m == NULL)
return IEEE80211_FC0_TYPE_DATA;

View File

@ -1074,9 +1074,11 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
* 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.
*/
addqos = (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) &&
(m->m_flags & M_EAPOL) == 0;
addqos = ((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
@ -1282,7 +1284,12 @@ ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni,
qos[0] = tid & IEEE80211_QOS_TID;
if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy)
qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK;
qos[1] = 0;
#ifdef IEEE80211_SUPPORT_MESH
if (vap->iv_opmode == IEEE80211_M_MBSS) {
qos[1] |= IEEE80211_QOS_MC;
} else
#endif
qos[1] = 0;
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS;
if ((m->m_flags & M_AMPDU_MPDU) == 0) {
@ -1407,9 +1414,20 @@ ieee80211_fragment(struct ieee80211vap *vap, struct mbuf *m0,
* we mark the first fragment with the MORE_FRAG bit
* it automatically is propagated to each fragment; we
* need only clear it on the last fragment (done below).
* NB: frag 1+ dont have Mesh Control field present.
*/
whf = mtod(m, struct ieee80211_frame *);
memcpy(whf, wh, hdrsize);
#ifdef IEEE80211_SUPPORT_MESH
if (vap->iv_opmode == IEEE80211_M_MBSS) {
if (IEEE80211_IS_DSTODS(wh))
((struct ieee80211_qosframe_addr4 *)
whf)->i_qos[1] &= ~IEEE80211_QOS_MC;
else
((struct ieee80211_qosframe *)
whf)->i_qos[1] &= ~IEEE80211_QOS_MC;
}
#endif
*(uint16_t *)&whf->i_seq[0] |= htole16(
(fragno & IEEE80211_SEQ_FRAG_MASK) <<
IEEE80211_SEQ_FRAG_SHIFT);