if (ic->ic_dev->flags & IFF_RUNNING) {
/* needs to disable hardware too */
-@@ -1271,8 +1269,12 @@ ath_vap_create(struct ieee80211com *ic,
+@@ -1271,8 +1269,12 @@ ath_vap_create(struct ieee80211com *ic,
} else
ic_opmode = opmode;
break;
/* permit multiple APs and/or WDS links */
/* XXX sta+ap for repeater/bridge application */
if ((sc->sc_nvaps != 0) && (ic->ic_opmode == IEEE80211_M_STA))
-@@ -1304,7 +1306,7 @@ ath_vap_create(struct ieee80211com *ic,
+@@ -1304,7 +1306,7 @@ ath_vap_create(struct ieee80211com *ic,
}
avp = dev->priv;
{
#define IEEE80211_C_OPMODE \
(IEEE80211_C_IBSS | IEEE80211_C_HOSTAP | IEEE80211_C_AHDEMO | \
-@@ -510,9 +525,18 @@ ieee80211_vap_setup(struct ieee80211com
+@@ -510,9 +525,18 @@ ieee80211_vap_setup(struct ieee80211com
vap->iv_monitor_crc_errors = 0;
vap->iv_monitor_phy_errors = 0;
switch (cmd) {
case SIOCG80211STATS:
-@@ -5921,8 +5922,20 @@ ieee80211_ioctl(struct net_device *dev,
+@@ -5921,8 +5922,20 @@ ieee80211_ioctl(struct net_device *dev,
case SIOC80211IFDESTROY:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
IEEE80211_NODE_STAT(ni, rx_data);
IEEE80211_NODE_STAT_ADD(ni, rx_bytes, skb->len);
ic->ic_lastdata = jiffies;
-@@ -1114,6 +1142,17 @@ ieee80211_deliver_data(struct ieee80211_
+@@ -1114,6 +1142,18 @@ ieee80211_deliver_data(struct ieee80211_
dev = vap->iv_xrvap->iv_dev;
#endif
+ if (ni->ni_subif && ((eh)->ether_type != __constant_htons(ETHERTYPE_PAE))) {
+ if (ni->ni_vap == ni->ni_subif) {
+ ieee80211_dev_kfree_skb(&skb);
++ return;
+ } else {
+ vap = ni->ni_subif;
+ dev = vap->iv_dev;
/* perform as a bridge within the vap */
/* XXX intra-vap bridging only */
if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
-@@ -1139,7 +1178,16 @@ ieee80211_deliver_data(struct ieee80211_
+@@ -1139,7 +1179,16 @@ ieee80211_deliver_data(struct ieee80211_
if (ni1 != NULL) {
if (ni1->ni_vap == vap &&
ieee80211_node_is_authorized(ni1) &&
skb1 = skb;
skb = NULL;
}
-@@ -3084,8 +3132,7 @@ ieee80211_recv_mgmt(struct ieee80211vap
+@@ -3084,8 +3133,7 @@ ieee80211_recv_mgmt(struct ieee80211vap
(vap->iv_opmode == IEEE80211_M_STA && ni->ni_associd) ||
(vap->iv_opmode == IEEE80211_M_IBSS) ||
((subtype == IEEE80211_FC0_SUBTYPE_BEACON) &&
vap->iv_stats.is_rx_mgtdiscard++;
return;
}
-@@ -3471,13 +3518,54 @@ ieee80211_recv_mgmt(struct ieee80211vap
+@@ -3471,13 +3519,56 @@ ieee80211_recv_mgmt(struct ieee80211vap
*/
if (ic->ic_flags & IEEE80211_F_SCAN) {
ieee80211_add_scan(vap, &scan, wh, subtype, rssi, rtsf);
+ if (!memcmp(avp->wds_mac, wh->i_addr2, IEEE80211_ADDR_LEN)) {
+ if (avp->iv_state != IEEE80211_S_RUN)
+ continue;
++ if (!avp->iv_wdsnode)
++ continue;
+ found = 1;
+ break;
+ }
+ }
+ if (found)
+ ni = ni_or_null = avp->iv_wdsnode;
-+ } else if (vap->iv_opmode == IEEE80211_M_WDS) {
++ } else if ((vap->iv_opmode == IEEE80211_M_WDS) && vap->iv_wdsnode) {
+ found = 1;
+ ni = ni_or_null = vap->iv_wdsnode;
+ }
} else {
/*
* Copy data from beacon to neighbor table.
-@@ -3490,6 +3578,7 @@ ieee80211_recv_mgmt(struct ieee80211vap
+@@ -3490,6 +3581,7 @@ ieee80211_recv_mgmt(struct ieee80211vap
IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3);
memcpy(ni->ni_tstamp.data, scan.tstamp,
sizeof(ni->ni_tstamp));
/* 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
+@@ -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.
*/
+ 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);
+ }
}
}
EXPORT_SYMBOL(ieee80211_stop_running);
-@@ -1342,9 +1398,9 @@ ieee80211_new_state(struct ieee80211vap
+@@ -1342,9 +1398,9 @@ ieee80211_new_state(struct ieee80211vap
struct ieee80211com *ic = vap->iv_ic;
int rc;