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;
rfilt |= HAL_RX_FILTER_BEACON;
if (sc->sc_nmonvaps > 0)
rfilt |= (HAL_RX_FILTER_CONTROL | HAL_RX_FILTER_BEACON |
-@@ -9030,8 +9031,6 @@ ath_calibrate(unsigned long arg)
+@@ -9032,8 +9033,6 @@ ath_calibrate(unsigned long arg)
* set sc->beacons if we might need to restart
* them after ath_reset. */
if (!sc->sc_beacons &&
{
#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);
+ (vap->iv_opmode == IEEE80211_M_WDS)) &&
+ (scan.capinfo & IEEE80211_CAPINFO_ESS))) {
+ struct ieee80211vap *avp = NULL;
++ int found = 0;
+
+ IEEE80211_LOCK_IRQ(vap->iv_ic);
+ if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
-+ int found = 0;
-+
+ TAILQ_FOREACH(avp, &vap->iv_wdslinks, iv_wdsnext) {
+ 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)
-+ break;
-+
-+ ni = ni_or_null = avp->iv_wdsnode;
-+ } else if (vap->iv_opmode == IEEE80211_M_WDS) {
++ if (found)
++ ni = ni_or_null = avp->iv_wdsnode;
++ } else if ((vap->iv_opmode == IEEE80211_M_WDS) && vap->iv_wdsnode) {
++ found = 1;
+ ni = ni_or_null = vap->iv_wdsnode;
+ }
+ IEEE80211_UNLOCK_IRQ(vap->iv_ic);
+
++ if (!found)
++ break;
+
if (ni_or_null == NULL) {
- /* Create a new entry in the neighbor table. */
} 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));
ieee80211_node_table_reset(&ic->ic_sta, vap);
if (vap->iv_bss != NULL) {
ieee80211_unref_node(&vap->iv_bss);
+@@ -309,7 +314,7 @@ ieee80211_create_ibss(struct ieee80211va
+ /* Check to see if we already have a node for this mac
+ * NB: we gain a node reference here
+ */
+- ni = ieee80211_find_node(&ic->ic_sta, vap->iv_myaddr);
++ ni = ieee80211_find_txnode(vap, vap->iv_myaddr);
+ if (ni == NULL) {
+ ni = ieee80211_alloc_node_table(vap, vap->iv_myaddr);
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
@@ -831,12 +836,18 @@ node_table_leave_locked(struct ieee80211
LIST_REMOVE(ni, ni_hash);
}
}
/* This is overridden by ath_node_alloc in ath/if_ath.c, and so
-@@ -1134,6 +1145,62 @@ ieee80211_alloc_node(struct ieee80211vap
+@@ -1134,6 +1145,65 @@ ieee80211_alloc_node(struct ieee80211vap
return ni;
}
+ if (ni->ni_subif)
+ return;
+
++ if (!ni->ni_table)
++ return;
++
+ ieee80211_ref_node(ni);
+ ni->ni_subif = ni->ni_vap;
+ IEEE80211_INIT_WORK(&ni->ni_create, ieee80211_wds_do_addif);
/* Add wds address to the node table */
int
#ifdef IEEE80211_DEBUG_REFCNT
-@@ -1553,22 +1620,39 @@ ieee80211_find_rxnode(struct ieee80211co
+@@ -1553,22 +1623,39 @@ ieee80211_find_rxnode(struct ieee80211co
((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL)
struct ieee80211_node_table *nt;
struct ieee80211_node *ni;
#endif
IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
-@@ -1596,9 +1680,19 @@ ieee80211_find_txnode_debug(struct ieee8
+@@ -1596,9 +1683,19 @@ ieee80211_find_txnode_debug(struct ieee8
ieee80211_find_txnode(struct ieee80211vap *vap, const u_int8_t *mac)
#endif
{
/*
* The destination address should be in the node table
* unless we are operating in station mode or this is a
-@@ -1669,6 +1763,11 @@ ieee80211_free_node(struct ieee80211_nod
+@@ -1669,6 +1766,11 @@ ieee80211_free_node(struct ieee80211_nod
{
struct ieee80211vap *vap = ni->ni_vap;
atomic_dec(&ni->ni_ic->ic_node_counter);
node_print_message(IEEE80211_MSG_NODE|IEEE80211_MSG_NODE_REF,
1 /* show counter */,
-@@ -1781,22 +1880,6 @@ restart:
+@@ -1781,22 +1883,6 @@ restart:
jiffies > ni->ni_rxfragstamp + HZ) {
ieee80211_dev_kfree_skb(&ni->ni_rxfrag);
}
ni->ni_inact--;
if (ni->ni_associd != 0 || isadhoc) {
struct ieee80211vap *vap = ni->ni_vap;
-@@ -2263,6 +2346,36 @@ ieee80211_node_leave_11g(struct ieee8021
+@@ -2263,6 +2349,35 @@ ieee80211_node_leave_11g(struct ieee8021
}
}
+ struct ieee80211vap *vap;
+ struct ieee80211com *ic;
+
++ /* wait for full initialization before we start the teardown
++ * otherwise we could leak interfaces */
++ while (ni->ni_subif == ni->ni_vap)
++ schedule();
++
+ rtnl_lock();
+ vap = ni->ni_subif;
+
-+ /* if addif is waiting for the timer to fire, cancel! */
-+ if (vap == ni->ni_vap) {
-+ ni->ni_subif = NULL;
-+ goto done;
-+ }
-+
+ if (!vap)
+ goto done;
+
/*
* Handle bookkeeping for a station/neighbor leaving
* the bss when operating in ap or adhoc modes.
-@@ -2279,6 +2392,12 @@ ieee80211_node_leave(struct ieee80211_no
+@@ -2279,6 +2394,12 @@ ieee80211_node_leave(struct ieee80211_no
ni, "station with aid %d leaves (refcnt %u)",
IEEE80211_NODE_AID(ni), atomic_read(&ni->ni_refcnt));
/* 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);
+ }
};
--- a/net80211/ieee80211_proto.c
+++ b/net80211/ieee80211_proto.c
-@@ -1081,6 +1081,8 @@ ieee80211_init(struct net_device *dev, i
+@@ -979,6 +979,12 @@ ieee80211_init(struct net_device *dev, i
+ "start running (state=%d)\n", vap->iv_state);
+
+
++ if (vap->iv_master && vap->iv_master->iv_state == IEEE80211_S_INIT) {
++ int ret = ieee80211_init(vap->iv_master->iv_dev, forcescan);
++ if (ret < 0)
++ return ret;
++ }
++
+ if ((dev->flags & IFF_RUNNING) == 0) {
+ if (ic->ic_nopened++ == 0 &&
+ (parent->flags & IFF_RUNNING) == 0)
+@@ -1081,6 +1087,8 @@ ieee80211_init(struct net_device *dev, i
int
ieee80211_open(struct net_device *dev)
{
return ieee80211_init(dev, 0);
}
-@@ -1090,7 +1092,7 @@ ieee80211_open(struct net_device *dev)
+@@ -1090,7 +1098,7 @@ ieee80211_open(struct net_device *dev)
void
ieee80211_start_running(struct ieee80211com *ic)
{
struct net_device *dev;
/* XXX locking */
-@@ -1099,6 +1101,16 @@ ieee80211_start_running(struct ieee80211
+@@ -1099,6 +1107,16 @@ ieee80211_start_running(struct ieee80211
/* NB: avoid recursion */
if ((dev->flags & IFF_UP) && !(dev->flags & IFF_RUNNING))
ieee80211_open(dev);
}
}
EXPORT_SYMBOL(ieee80211_start_running);
-@@ -1116,11 +1128,43 @@ ieee80211_stop(struct net_device *dev)
+@@ -1116,11 +1134,43 @@ ieee80211_stop(struct net_device *dev)
struct ieee80211vap *vap = dev->priv;
struct ieee80211com *ic = vap->iv_ic;
struct net_device *parent = ic->ic_dev;
ieee80211_new_state(vap, IEEE80211_S_INIT, -1);
if (dev->flags & IFF_RUNNING) {
dev->flags &= ~IFF_RUNNING; /* mark us stopped */
-@@ -1148,7 +1192,7 @@ EXPORT_SYMBOL(ieee80211_stop);
+@@ -1148,7 +1198,7 @@ EXPORT_SYMBOL(ieee80211_stop);
void
ieee80211_stop_running(struct ieee80211com *ic)
{
struct net_device *dev;
/* XXX locking */
-@@ -1156,6 +1200,12 @@ ieee80211_stop_running(struct ieee80211c
+@@ -1156,6 +1206,12 @@ ieee80211_stop_running(struct ieee80211c
dev = vap->iv_dev;
if (dev->flags & IFF_RUNNING) /* NB: avoid recursion */
ieee80211_stop(dev);
}
}
EXPORT_SYMBOL(ieee80211_stop_running);
-@@ -1342,9 +1392,9 @@ ieee80211_new_state(struct ieee80211vap
+@@ -1342,9 +1398,9 @@ ieee80211_new_state(struct ieee80211vap
struct ieee80211com *ic = vap->iv_ic;
int rc;
return rc;
}
-@@ -1557,57 +1607,12 @@ __ieee80211_newstate(struct ieee80211vap
+@@ -1557,57 +1613,12 @@ __ieee80211_newstate(struct ieee80211vap
switch (ostate) {
case IEEE80211_S_INIT:
if (vap->iv_opmode == IEEE80211_M_MONITOR ||
break;
}
/* fall thru... */
-@@ -1675,6 +1680,7 @@ __ieee80211_newstate(struct ieee80211vap
+@@ -1675,6 +1686,7 @@ __ieee80211_newstate(struct ieee80211vap
*/
if (ni->ni_authmode != IEEE80211_AUTH_8021X)
ieee80211_node_authorize(ni);
#ifdef ATH_SUPERG_XR
/*
* fire a timer to bring up XR vap if configured.
-@@ -1808,6 +1814,11 @@ ieee80211_newstate(struct ieee80211vap *
+@@ -1808,6 +1820,11 @@ ieee80211_newstate(struct ieee80211vap *
ieee80211_state_name[dstate]);
ieee80211_update_link_status(vap, nstate, ostate);
switch (nstate) {
case IEEE80211_S_AUTH:
case IEEE80211_S_ASSOC:
-@@ -1930,8 +1941,15 @@ ieee80211_newstate(struct ieee80211vap *
+@@ -1930,8 +1947,15 @@ ieee80211_newstate(struct ieee80211vap *
if (ostate == IEEE80211_S_SCAN ||
ostate == IEEE80211_S_AUTH ||
ostate == IEEE80211_S_ASSOC) {