if (skb->len < hdrspace) {
IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
wh, "data", "too short: len %u, expecting %u",
-@@ -446,15 +447,20 @@
+@@ -445,16 +446,24 @@
+ }
switch (vap->iv_opmode) {
case IEEE80211_M_STA:
- if ((dir != IEEE80211_FC1_DIR_FROMDS) &&
+- if ((dir != IEEE80211_FC1_DIR_FROMDS) &&
- (!((vap->iv_flags_ext & IEEE80211_FEXT_WDS) &&
- (dir == IEEE80211_FC1_DIR_DSTODS)))) {
-+ (!(vap->iv_flags_ext & IEEE80211_FEXT_WDS) &&
-+ (dir == IEEE80211_FC1_DIR_DSTODS))) {
++ switch(dir) {
++ case IEEE80211_FC1_DIR_FROMDS:
++ break;
++ case IEEE80211_FC1_DIR_DSTODS:
++ if (vap->iv_flags_ext & IEEE80211_FEXT_WDS)
++ break;
++ default:
IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
wh, "data", "invalid dir 0x%x", dir);
vap->iv_stats.is_rx_wrongdir++;
- if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+ if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
+ /* ignore 3-addr mcast if we're WDS STA */
-+ if ((vap->iv_flags_ext & IEEE80211_FEXT_WDS) &&
-+ (dir != IEEE80211_FC1_DIR_DSTODS))
++ if (vap->iv_flags_ext & IEEE80211_FEXT_WDS)
+ goto out;
+
/* Discard multicast if IFF_MULTICAST not set */
if ((0 != memcmp(wh->i_addr3, dev->broadcast, ETH_ALEN)) &&
(0 == (dev->flags & IFF_MULTICAST))) {
-@@ -482,24 +488,6 @@
+@@ -482,24 +491,10 @@
vap->iv_stats.is_rx_mcastecho++;
goto out;
}
- goto out;
- }
- }
++ } else {
++ /* Same BSSID, but not meant for us to receive */
++ if (!IEEE80211_ADDR_EQ(wh->i_addr1, vap->iv_myaddr))
++ goto out;
}
break;
case IEEE80211_M_IBSS:
-@@ -548,7 +536,7 @@
+@@ -541,6 +536,11 @@
+ vap->iv_stats.is_rx_notassoc++;
+ goto err;
+ }
++
++ /* subif isn't fully set up yet, drop the frame */
++ if (ni->ni_subif == ni->ni_vap)
++ goto err;
++
+ /*
+ * If we're a 4 address packet, make sure we have an entry in
+ * the node table for the packet source address (addr4).
+@@ -548,9 +548,16 @@
*/
/* check for wds link first */
+ if ((dir == IEEE80211_FC1_DIR_DSTODS) && !ni->ni_subif) {
struct ieee80211vap *avp;
- TAILQ_FOREACH(avp, &vap->iv_wdslinks, iv_wdsnext) {
-@@ -562,11 +550,13 @@
- if (ni_wds != NULL) {
- ieee80211_unref_node(&ni);
- ni = ieee80211_ref_node(ni_wds);
-+ } else if (vap->iv_flags_ext & IEEE80211_FEXT_WDSSEP) {
++ if (vap->iv_flags_ext & IEEE80211_FEXT_WDSSEP) {
+ ieee80211_wds_addif(ni);
- }
++ /* we must drop frames here until the interface has
++ * been fully separated, otherwise a bridge might get
++ * confused */
++ goto err;
++ }
+ TAILQ_FOREACH(avp, &vap->iv_wdslinks, iv_wdsnext) {
+ if (!memcmp(avp->wds_mac, wh->i_addr2, IEEE80211_ADDR_LEN)) {
+ IEEE80211_LOCK_IRQ(ni->ni_ic);
+@@ -566,7 +573,7 @@
}
/* XXX: Useless node mgmt API; make better */
struct ieee80211_node_table *nt = &ic->ic_sta;
struct ieee80211_frame_addr4 *wh4;
-@@ -626,6 +616,11 @@
+@@ -626,6 +633,11 @@
goto out;
}
/*
* Handle privacy requirements. Note that we
* must not be preempted from here until after
-@@ -698,8 +693,12 @@
+@@ -698,8 +710,12 @@
if (! accept_data_frame(vap, ni, key, skb, eh))
goto out;
IEEE80211_NODE_STAT(ni, rx_data);
IEEE80211_NODE_STAT_ADD(ni, rx_bytes, skb->len);
ic->ic_lastdata = jiffies;
-@@ -1132,6 +1131,13 @@
+@@ -1132,6 +1148,13 @@
dev = vap->iv_xrvap->iv_dev;
#endif
/* perform as a bridge within the vap */
/* XXX intra-vap bridging only */
if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
-@@ -1157,6 +1163,7 @@
+@@ -1157,7 +1180,16 @@
if (ni1 != NULL) {
if (ni1->ni_vap == vap &&
ieee80211_node_is_authorized(ni1) &&
-+ !ni->ni_subif &&
++ !ni1->ni_subif &&
ni1 != vap->iv_bss) {
++
++ /* tried to bridge to a subif, drop the packet */
++ if (ni->ni_subif) {
++ ieee80211_unref_node(&ni1);
++ ieee80211_dev_kfree_skb(&skb);
++ return;
++ }
++
skb1 = skb;
skb = NULL;
+ }
--- a/net80211/ieee80211_ioctl.h
+++ b/net80211/ieee80211_ioctl.h
@@ -649,6 +649,7 @@
default:
return -EOPNOTSUPP;
}
-@@ -5767,6 +5778,10 @@
+@@ -4447,6 +4458,8 @@
+ struct ieee80211vap *vap = ni->ni_vap;
+ size_t ielen;
+
++ if (req->vap->iv_wdsnode && ni->ni_subif)
++ vap = ni->ni_subif;
+ if (vap != req->vap && vap != req->vap->iv_xrvap) /* only entries for this vap */
+ return;
+ if ((vap->iv_opmode == IEEE80211_M_HOSTAP ||
+@@ -4466,6 +4479,8 @@
+ size_t ielen, len;
+ u_int8_t *cp;
+
++ if (req->vap->iv_wdsnode && ni->ni_subif)
++ vap = ni->ni_subif;
+ if (vap != req->vap && vap != req->vap->iv_xrvap) /* only entries for this vap (or) xrvap */
+ return;
+ if ((vap->iv_opmode == IEEE80211_M_HOSTAP ||
+@@ -5767,6 +5782,10 @@
0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_minrate"},
{ IEEE80211_IOCTL_SETSCANLIST,
IW_PRIV_TYPE_CHAR | 255, 0, "setscanlist"},
#ifdef ATH_REVERSE_ENGINEERING
/*
-@@ -5890,6 +5905,8 @@
+@@ -5890,6 +5909,8 @@
ieee80211_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
struct ieee80211vap *vap = dev->priv;
switch (cmd) {
case SIOCG80211STATS:
-@@ -5898,8 +5915,20 @@
+@@ -5898,8 +5919,20 @@
case SIOC80211IFDESTROY:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
/* Locking */
/* NB: beware, spin_is_locked() is not usefully defined for !(DEBUG || SMP)
* because spinlocks do not exist in this configuration. Instead IRQs
-@@ -167,6 +196,18 @@
- IEEE80211_VAPS_LOCK_ASSERT(_ic); \
- spin_unlock_bh(&(_ic)->ic_vapslock); \
- } while (0)
-+#define IEEE80211_VAPS_LOCK_IRQ(_ic) do { \
-+ unsigned long __vlockflags; \
-+ IEEE80211_VAPS_LOCK_CHECK(_ic); \
-+ spin_lock_irqsave(&(_ic)->ic_vapslock, __vlockflags);
-+#define IEEE80211_VAPS_UNLOCK_IRQ(_ic) \
-+ IEEE80211_VAPS_LOCK_ASSERT(_ic); \
-+ spin_unlock_irqrestore(&(_ic)->ic_vapslock, __vlockflags); \
-+} while (0)
-+#define IEEE80211_VAPS_UNLOCK_IRQ_EARLY(_ic) \
-+ IEEE80211_VAPS_LOCK_ASSERT(_ic); \
-+ spin_unlock_irqrestore(&(_ic)->ic_vapslock, __vlockflags);
-+
-
- #if (defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)) && defined(spin_is_locked)
- #define IEEE80211_VAPS_LOCK_ASSERT(_ic) \
--- a/net80211/ieee80211_proto.c
+++ b/net80211/ieee80211_proto.c
@@ -1081,6 +1081,8 @@
ieee80211_new_state(vap, IEEE80211_S_INIT, -1);
if (dev->flags & IFF_RUNNING) {
dev->flags &= ~IFF_RUNNING; /* mark us stopped */
-@@ -1342,9 +1366,9 @@
- struct ieee80211com *ic = vap->iv_ic;
- int rc;
-
-- IEEE80211_VAPS_LOCK_BH(ic);
-+ IEEE80211_VAPS_LOCK_IRQ(ic);
- rc = vap->iv_newstate(vap, nstate, arg);
-- IEEE80211_VAPS_UNLOCK_BH(ic);
-+ IEEE80211_VAPS_UNLOCK_IRQ(ic);
- return rc;
- }
-
@@ -1630,6 +1654,7 @@
*/
if (ni->ni_authmode != IEEE80211_AUTH_8021X)
hdrsize = sizeof(struct ieee80211_frame);
SKB_CB(skb)->auth_pkt = (eh.ether_type == __constant_htons(ETHERTYPE_PAE));
-+ if (!SKB_CB(skb)->auth_pkt && ni->ni_subif)
++ if (ni->ni_subif)
+ vap = ni->ni_subif;
switch (vap->iv_opmode) {