+ }
+
++ if (ni->ni_subif && (vap != ni->ni_subif) &&
++ ((eh)->ether_type != __constant_htons(ETHERTYPE_PAE)))
++ goto bad;
++
+ /* calculate priority so drivers can find the TX queue */
+ if (ieee80211_classify(ni, skb)) {
+ IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni,
+@@ -334,20 +335,33 @@ void ieee80211_parent_queue_xmit(struct
+ * constructing a frame as it sets i_fc[1]; other bits can
+ * then be or'd in.
+ */
+-static void
++static struct ieee80211_frame *
+ ieee80211_send_setup(struct ieee80211vap *vap,
+ struct ieee80211_node *ni,
+- struct ieee80211_frame *wh,
++ struct sk_buff *skb,
+ int type,
+ const u_int8_t sa[IEEE80211_ADDR_LEN],
+ const u_int8_t da[IEEE80211_ADDR_LEN],
+ const u_int8_t bssid[IEEE80211_ADDR_LEN])
+ {
+ #define WH4(wh) ((struct ieee80211_frame_addr4 *)wh)
++ struct ieee80211_frame *wh;
++ int len = sizeof(struct ieee80211_frame);
++ int opmode = vap->iv_opmode;
++
++ if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {
++ if ((opmode == IEEE80211_M_STA) &&
++ (vap->iv_flags_ext & IEEE80211_FEXT_WDS))
++ opmode = IEEE80211_M_WDS;
+
++ if (opmode == IEEE80211_M_WDS)
++ len = sizeof(struct ieee80211_frame_addr4);
++ }
++
++ wh = (struct ieee80211_frame *)skb_push(skb, len);
+ wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type;
+ if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {
+- switch (vap->iv_opmode) {
++ switch (opmode) {
+ case IEEE80211_M_STA:
+ wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
+ IEEE80211_ADDR_COPY(wh->i_addr1, bssid);
+@@ -389,6 +403,8 @@ ieee80211_send_setup(struct ieee80211vap
+ *(__le16 *)&wh->i_seq[0] =
+ htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT);
+ ni->ni_txseqs[0]++;
++
++ return wh;
+ #undef WH4
+ }
+
+@@ -410,9 +426,7 @@ ieee80211_mgmt_output(struct ieee80211_n
+
+ SKB_CB(skb)->ni = ni;
+
+- wh = (struct ieee80211_frame *)
+- skb_push(skb, sizeof(struct ieee80211_frame));
+- ieee80211_send_setup(vap, ni, wh,
++ wh = ieee80211_send_setup(vap, ni, skb,
+ IEEE80211_FC0_TYPE_MGT | type,
+ vap->iv_myaddr, ni->ni_macaddr, vap->iv_bssid);
+ /* XXX power management */
+@@ -458,6 +472,9 @@ ieee80211_send_nulldata(struct ieee80211
+ struct ieee80211_frame *wh;
+ u_int8_t *frm;
+
++ if (ni->ni_subif)
++ vap = ni->ni_subif;
++
+ skb = ieee80211_getmgtframe(&frm, 0);
+ if (skb == NULL) {
+ /* XXX debug msg */
+@@ -466,9 +483,7 @@ ieee80211_send_nulldata(struct ieee80211
+ return -ENOMEM;
+ }
+
+- wh = (struct ieee80211_frame *)
+- skb_push(skb, sizeof(struct ieee80211_frame));
+- ieee80211_send_setup(vap, ni, wh,
++ wh = ieee80211_send_setup(vap, ni, skb,
+ IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA,
+ vap->iv_myaddr, ni->ni_macaddr, vap->iv_bssid);
+ /* NB: power management bit is never sent by an AP */
+@@ -506,6 +521,7 @@ ieee80211_send_qosnulldata(struct ieee80
+ struct sk_buff *skb;
+ struct ieee80211_qosframe *qwh;
+ u_int8_t *frm;
++ u_int8_t *i_qos;
+ int tid;
+
+ skb = ieee80211_getmgtframe(&frm, 2);
+@@ -517,11 +533,12 @@ ieee80211_send_qosnulldata(struct ieee80
+ SKB_CB(skb)->ni = ieee80211_ref_node(ni);
+
+ skb->priority = ac;
+- qwh = (struct ieee80211_qosframe *)skb_push(skb, sizeof(struct ieee80211_qosframe));
+
+- qwh = (struct ieee80211_qosframe *)skb->data;
++ /* grab a pointer to QoS control and also compensate for the header length
++ * difference between QoS and non-QoS frame */
++ i_qos = skb_push(skb, sizeof(struct ieee80211_qosframe) - sizeof(struct ieee80211_frame));
+
+- ieee80211_send_setup(vap, ni, (struct ieee80211_frame *)qwh,
++ qwh = (struct ieee80211_qosframe *) ieee80211_send_setup(vap, ni, skb,
+ IEEE80211_FC0_TYPE_DATA,
+ vap->iv_myaddr, /* SA */
+ ni->ni_macaddr, /* DA */
+@@ -535,10 +552,10 @@ ieee80211_send_qosnulldata(struct ieee80
+
+ /* map from access class/queue to 11e header priority value */
+ tid = WME_AC_TO_TID(ac);
+- qwh->i_qos[0] = tid & IEEE80211_QOS_TID;
++ i_qos[0] = tid & IEEE80211_QOS_TID;
+ if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy)
+ qwh->i_qos[0] |= (1 << IEEE80211_QOS_ACKPOLICY_S) & IEEE80211_QOS_ACKPOLICY;
+- qwh->i_qos[1] = 0;
++ i_qos[1] = 0;
+
+ IEEE80211_NODE_STAT(ni, tx_data);
+
+@@ -780,6 +797,8 @@ ieee80211_encap(struct ieee80211_node *n
+ hdrsize = sizeof(struct ieee80211_frame);
+
+ SKB_CB(skb)->auth_pkt = (eh.ether_type == __constant_htons(ETHERTYPE_PAE));
++ if (ni->ni_subif)
++ vap = ni->ni_subif;
+
+ switch (vap->iv_opmode) {
+ case IEEE80211_M_IBSS:
+@@ -788,7 +807,7 @@ ieee80211_encap(struct ieee80211_node *n