Root/package/madwifi/patches/370-wdsvap.patch

1--- a/ath/if_ath.c
2+++ b/ath/if_ath.c
3@@ -124,7 +124,7 @@ enum {
4 };
5 
6 static struct ieee80211vap *ath_vap_create(struct ieee80211com *,
7- const char *, int, int, struct net_device *);
8+ const char *, int, int, struct net_device *, struct ieee80211vap *);
9 static void ath_vap_delete(struct ieee80211vap *);
10 static int ath_init(struct net_device *);
11 static int ath_set_ack_bitrate(struct ath_softc *, int);
12@@ -1123,8 +1123,6 @@ ath_attach(u_int16_t devid, struct net_d
13             autocreatemode = IEEE80211_M_IBSS;
14         else if (!strcmp(autocreate, "ahdemo"))
15             autocreatemode = IEEE80211_M_AHDEMO;
16- else if (!strcmp(autocreate, "wds"))
17- autocreatemode = IEEE80211_M_WDS;
18         else if (!strcmp(autocreate, "monitor"))
19             autocreatemode = IEEE80211_M_MONITOR;
20         else {
21@@ -1137,7 +1135,7 @@ ath_attach(u_int16_t devid, struct net_d
22     if (autocreatemode != -1) {
23         rtnl_lock();
24         vap = ieee80211_create_vap(ic, "ath%d", dev,
25- autocreatemode, 0);
26+ autocreatemode, 0, NULL);
27         rtnl_unlock();
28         if (vap == NULL)
29             EPRINTF(sc, "Autocreation of %s VAP failed.", autocreate);
30@@ -1230,14 +1228,14 @@ ath_detach(struct net_device *dev)
31 
32 static struct ieee80211vap *
33 ath_vap_create(struct ieee80211com *ic, const char *name,
34- int opmode, int flags, struct net_device *mdev)
35+ int opmode, int flags, struct net_device *mdev, struct ieee80211vap *master)
36 {
37     struct ath_softc *sc = ic->ic_dev->priv;
38     struct ath_hal *ah = sc->sc_ah;
39     struct net_device *dev;
40     struct ath_vap *avp;
41     struct ieee80211vap *vap;
42- int ic_opmode;
43+ int ic_opmode = IEEE80211_M_STA;
44 
45     if (ic->ic_dev->flags & IFF_RUNNING) {
46         /* needs to disable hardware too */
47@@ -1271,8 +1269,12 @@ ath_vap_create(struct ieee80211com *ic,
48         } else
49             ic_opmode = opmode;
50         break;
51- case IEEE80211_M_HOSTAP:
52     case IEEE80211_M_WDS:
53+ ic_opmode = ic->ic_opmode;
54+ if (!master)
55+ return NULL;
56+ break;
57+ case IEEE80211_M_HOSTAP:
58         /* permit multiple APs and/or WDS links */
59         /* XXX sta+ap for repeater/bridge application */
60         if ((sc->sc_nvaps != 0) && (ic->ic_opmode == IEEE80211_M_STA))
61@@ -1304,7 +1306,7 @@ ath_vap_create(struct ieee80211com *ic,
62     }
63 
64     avp = dev->priv;
65- ieee80211_vap_setup(ic, dev, name, opmode, flags);
66+ ieee80211_vap_setup(ic, dev, name, opmode, flags, master);
67     /* override with driver methods */
68     vap = &avp->av_vap;
69     avp->av_newstate = vap->iv_newstate;
70@@ -4209,8 +4211,7 @@ ath_calcrxfilter(struct ath_softc *sc)
71     if (ic->ic_opmode == IEEE80211_M_STA ||
72         sc->sc_opmode == HAL_M_IBSS || /* NB: AHDEMO too */
73         (sc->sc_nostabeacons) || sc->sc_scanning ||
74- ((ic->ic_opmode == IEEE80211_M_HOSTAP) &&
75- (ic->ic_protmode != IEEE80211_PROT_NONE)))
76+ (ic->ic_opmode == IEEE80211_M_HOSTAP))
77         rfilt |= HAL_RX_FILTER_BEACON;
78     if (sc->sc_nmonvaps > 0)
79         rfilt |= (HAL_RX_FILTER_CONTROL | HAL_RX_FILTER_BEACON |
80@@ -9032,8 +9033,6 @@ ath_calibrate(unsigned long arg)
81          * set sc->beacons if we might need to restart
82                  * them after ath_reset. */
83         if (!sc->sc_beacons &&
84- (TAILQ_FIRST(&ic->ic_vaps)->iv_opmode !=
85- IEEE80211_M_WDS) &&
86                 !txcont_was_active &&
87                 !sc->sc_dfs_cac) {
88             sc->sc_beacons = 1;
89--- a/net80211/ieee80211.c
90+++ b/net80211/ieee80211.c
91@@ -373,10 +373,25 @@ void
92 ieee80211_ifdetach(struct ieee80211com *ic)
93 {
94     struct ieee80211vap *vap;
95+ int count;
96+
97+ /* bring down all vaps */
98+ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
99+ ieee80211_stop(vap->iv_dev);
100+ }
101+
102+ /* wait for all subifs to disappear */
103+ do {
104+ schedule();
105+ rtnl_lock();
106+ count = ic->ic_subifs;
107+ rtnl_unlock();
108+ } while (count > 0);
109 
110     rtnl_lock();
111- while ((vap = TAILQ_FIRST(&ic->ic_vaps)) != NULL)
112+ while ((vap = TAILQ_FIRST(&ic->ic_vaps)) != NULL) {
113         ic->ic_vap_delete(vap);
114+ }
115     rtnl_unlock();
116 
117     del_timer(&ic->ic_dfs_excl_timer);
118@@ -396,7 +411,7 @@ EXPORT_SYMBOL(ieee80211_ifdetach);
119 
120 int
121 ieee80211_vap_setup(struct ieee80211com *ic, struct net_device *dev,
122- const char *name, int opmode, int flags)
123+ const char *name, int opmode, int flags, struct ieee80211vap *master)
124 {
125 #define IEEE80211_C_OPMODE \
126     (IEEE80211_C_IBSS | IEEE80211_C_HOSTAP | IEEE80211_C_AHDEMO | \
127@@ -510,9 +525,18 @@ ieee80211_vap_setup(struct ieee80211com
128 
129     vap->iv_monitor_crc_errors = 0;
130     vap->iv_monitor_phy_errors = 0;
131+ TAILQ_INIT(&vap->iv_wdslinks);
132 
133- IEEE80211_ADDR_COPY(vap->iv_myaddr, ic->ic_myaddr);
134- IEEE80211_ADDR_COPY(vap->iv_bssid, ic->ic_myaddr);
135+ if (master && (vap->iv_opmode == IEEE80211_M_WDS)) {
136+ vap->iv_master = master;
137+ TAILQ_INSERT_TAIL(&master->iv_wdslinks, vap, iv_wdsnext);
138+ /* use the same BSSID as the master interface */
139+ IEEE80211_ADDR_COPY(vap->iv_myaddr, vap->iv_master->iv_myaddr);
140+ IEEE80211_ADDR_COPY(vap->iv_bssid, vap->iv_master->iv_myaddr);
141+ } else {
142+ IEEE80211_ADDR_COPY(vap->iv_myaddr, ic->ic_myaddr);
143+ IEEE80211_ADDR_COPY(vap->iv_bssid, ic->ic_myaddr);
144+ }
145     /* NB: Defer setting dev_addr so driver can override */
146 
147     ieee80211_crypto_vattach(vap);
148@@ -547,7 +571,8 @@ ieee80211_vap_attach(struct ieee80211vap
149     ifmedia_set(&vap->iv_media, imr.ifm_active);
150 
151     IEEE80211_LOCK_IRQ(ic);
152- TAILQ_INSERT_TAIL(&ic->ic_vaps, vap, iv_next);
153+ if (vap->iv_opmode != IEEE80211_M_WDS)
154+ TAILQ_INSERT_TAIL(&ic->ic_vaps, vap, iv_next);
155     IEEE80211_UNLOCK_IRQ(ic);
156 
157     IEEE80211_ADDR_COPY(dev->dev_addr, vap->iv_myaddr);
158@@ -579,10 +604,27 @@ ieee80211_vap_detach(struct ieee80211vap
159 {
160     struct ieee80211com *ic = vap->iv_ic;
161     struct net_device *dev = vap->iv_dev;
162+ struct ieee80211vap *avp;
163+
164+ /* Drop all WDS links that belong to this vap */
165+ while ((avp = TAILQ_FIRST(&vap->iv_wdslinks)) != NULL) {
166+ if (avp->iv_state != IEEE80211_S_INIT)
167+ ieee80211_stop(avp->iv_dev);
168+ ic->ic_vap_delete(avp);
169+ }
170 
171     IEEE80211_CANCEL_TQUEUE(&vap->iv_stajoin1tq);
172     IEEE80211_LOCK_IRQ(ic);
173- TAILQ_REMOVE(&ic->ic_vaps, vap, iv_next);
174+ if (vap->iv_wdsnode) {
175+ vap->iv_wdsnode->ni_subif = NULL;
176+ ieee80211_unref_node(&vap->iv_wdsnode);
177+ }
178+ if ((vap->iv_opmode == IEEE80211_M_WDS) &&
179+ (vap->iv_master != NULL))
180+ TAILQ_REMOVE(&vap->iv_master->iv_wdslinks, vap, iv_wdsnext);
181+ else
182+ TAILQ_REMOVE(&ic->ic_vaps, vap, iv_next);
183+
184     if (TAILQ_EMPTY(&ic->ic_vaps)) /* reset to supported mode */
185         ic->ic_opmode = IEEE80211_M_STA;
186     IEEE80211_UNLOCK_IRQ(ic);
187--- a/net80211/ieee80211_ioctl.h
188+++ b/net80211/ieee80211_ioctl.h
189@@ -474,7 +474,7 @@ struct ieee80211req {
190 #define IEEE80211_IOC_DTIM_PERIOD 52 /* DTIM period (beacons) */
191 #define IEEE80211_IOC_BEACON_INTERVAL 53 /* beacon interval (ms) */
192 #define IEEE80211_IOC_ADDMAC 54 /* add sta to MAC ACL table */
193-#define IEEE80211_IOC_DELMAC 55 /* del sta from MAC ACL table */
194+#define IEEE80211_IOC_SETMAC 55 /* set interface wds mac addr */
195 #define IEEE80211_IOC_FF 56 /* ATH fast frames (on, off) */
196 #define IEEE80211_IOC_TURBOP 57 /* ATH turbo' (on, off) */
197 #define IEEE80211_IOC_APPIEBUF 58 /* IE in the management frame */
198@@ -552,8 +552,8 @@ struct ieee80211req_scan_result {
199 #define IEEE80211_IOCTL_HALMAP (SIOCIWFIRSTPRIV+21)
200 #define IEEE80211_IOCTL_ADDMAC (SIOCIWFIRSTPRIV+22)
201 #define IEEE80211_IOCTL_DELMAC (SIOCIWFIRSTPRIV+24)
202-#define IEEE80211_IOCTL_WDSADDMAC (SIOCIWFIRSTPRIV+26)
203-#define IEEE80211_IOCTL_WDSDELMAC (SIOCIWFIRSTPRIV+28)
204+#define IEEE80211_IOCTL_WDSADDMAC (SIOCIWFIRSTPRIV+25)
205+#define IEEE80211_IOCTL_WDSSETMAC (SIOCIWFIRSTPRIV+26)
206 #define IEEE80211_IOCTL_KICKMAC (SIOCIWFIRSTPRIV+30)
207 #define IEEE80211_IOCTL_SETSCANLIST (SIOCIWFIRSTPRIV+31)
208 
209@@ -649,6 +649,7 @@ enum {
210     IEEE80211_PARAM_BGSCAN_THRESH = 79, /* bg scan rssi threshold */
211     IEEE80211_PARAM_RSSI_DIS_THR = 80, /* rssi threshold for disconnection */
212     IEEE80211_PARAM_RSSI_DIS_COUNT = 81, /* counter for rssi threshold */
213+ IEEE80211_PARAM_WDS_SEP = 82, /* move wds stations into separate interfaces */
214 };
215 
216 #define SIOCG80211STATS (SIOCDEVPRIVATE+2)
217--- a/net80211/ieee80211_linux.h
218+++ b/net80211/ieee80211_linux.h
219@@ -81,6 +81,12 @@ set_quality(struct iw_quality *iq, u_int
220 #endif
221 }
222 
223+#ifndef container_of
224+#define container_of(ptr, type, member) ({ \
225+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
226+ (type *)( (char *)__mptr - offsetof(type,member) );})
227+#endif
228+
229 /*
230  * Task deferral
231  *
232@@ -113,6 +119,29 @@ typedef void *IEEE80211_TQUEUE_ARG;
233 
234 #define IEEE80211_RESCHEDULE schedule
235 
236+#include <linux/sched.h>
237+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41)
238+#include <linux/tqueue.h>
239+#define work_struct tq_struct
240+#define schedule_work(t) schedule_task((t))
241+#define flush_scheduled_work() flush_scheduled_tasks()
242+#define IEEE80211_INIT_WORK(t, f) do { \
243+ memset((t), 0, sizeof(struct tq_struct)); \
244+ (t)->routine = (void (*)(void*)) (f); \
245+ (t)->data=(void *) (t); \
246+} while (0)
247+#else
248+#include <linux/workqueue.h>
249+
250+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
251+#define IEEE80211_INIT_WORK(_t, _f) INIT_WORK((_t), (void (*)(void *))(_f), (_t));
252+#else
253+#define IEEE80211_INIT_WORK(_t, _f) INIT_WORK((_t), (_f));
254+#endif
255+
256+#endif /* KERNEL_VERSION < 2.5.41 */
257+
258+
259 /* Locking */
260 /* NB: beware, spin_is_locked() is not usefully defined for !(DEBUG || SMP)
261  * because spinlocks do not exist in this configuration. Instead IRQs
262@@ -167,6 +196,14 @@ typedef spinlock_t ieee80211com_lock_t;
263     IEEE80211_VAPS_LOCK_ASSERT(_ic); \
264     spin_unlock_bh(&(_ic)->ic_vapslock); \
265 } while (0)
266+#define IEEE80211_VAPS_LOCK_IRQ(_ic) do { \
267+ unsigned long __ilockflags; \
268+ IEEE80211_VAPS_LOCK_CHECK(_ic); \
269+ spin_lock_irqsave(&(_ic)->ic_vapslock, __ilockflags);
270+#define IEEE80211_VAPS_UNLOCK_IRQ(_ic) \
271+ IEEE80211_VAPS_LOCK_ASSERT(_ic); \
272+ spin_unlock_irqrestore(&(_ic)->ic_vapslock, __ilockflags); \
273+} while (0)
274 
275 #if (defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)) && defined(spin_is_locked)
276 #define IEEE80211_VAPS_LOCK_ASSERT(_ic) \
277@@ -650,5 +687,5 @@ struct ifreq;
278 int ieee80211_ioctl_create_vap(struct ieee80211com *, struct ifreq *,
279     struct net_device *);
280 struct ieee80211vap *ieee80211_create_vap(struct ieee80211com *, char *,
281- struct net_device *, int, int);
282+ struct net_device *, int, int, struct ieee80211vap *);
283 #endif /* _NET80211_IEEE80211_LINUX_H_ */
284--- a/net80211/ieee80211_var.h
285+++ b/net80211/ieee80211_var.h
286@@ -187,6 +187,12 @@ struct ieee80211vap {
287     struct ieee80211_proc_entry *iv_proc_entries;
288     struct vlan_group *iv_vlgrp; /* vlan group state */
289 
290+ /* list of wds links */
291+ TAILQ_HEAD(, ieee80211vap) iv_wdslinks;
292+ TAILQ_ENTRY(ieee80211vap) iv_wdsnext;
293+ struct ieee80211vap *iv_master;
294+ struct ieee80211_node *iv_wdsnode;
295+
296     TAILQ_ENTRY(ieee80211vap) iv_next; /* list of vap instances */
297     struct ieee80211com *iv_ic; /* back ptr to common state */
298     u_int32_t iv_debug; /* debug msg flags */
299@@ -316,6 +322,7 @@ struct ieee80211com {
300     u_int8_t ic_myaddr[IEEE80211_ADDR_LEN];
301     struct timer_list ic_inact; /* mgmt/inactivity timer */
302 
303+ unsigned int ic_subifs;
304     u_int32_t ic_flags; /* state flags */
305     u_int32_t ic_flags_ext; /* extension of state flags */
306     u_int32_t ic_caps; /* capabilities */
307@@ -447,7 +454,7 @@ struct ieee80211com {
308     atomic_t ic_node_counter;
309     /* Virtual AP create/delete */
310     struct ieee80211vap *(*ic_vap_create)(struct ieee80211com *,
311- const char *, int, int, struct net_device *);
312+ const char *, int, int, struct net_device *, struct ieee80211vap *);
313     void (*ic_vap_delete)(struct ieee80211vap *);
314 
315     /* Send/recv 802.11 management frame */
316@@ -619,6 +626,7 @@ MALLOC_DECLARE(M_80211_VAP);
317 #define IEEE80211_FEXT_DROPUNENC_EAPOL 0x00000800 /* CONF: drop unencrypted eapol frames */
318 #define IEEE80211_FEXT_APPIE_UPDATE 0x00001000 /* STATE: beacon APP IE updated */
319 #define IEEE80211_FEXT_BGSCAN_THR 0x00002000 /* bgscan due to low rssi */
320+#define IEEE80211_FEXT_WDSSEP 0x00004000 /* move wds clients into separate interfaces */
321 
322 #define IEEE80211_COM_UAPSD_ENABLE(_ic) ((_ic)->ic_flags_ext |= IEEE80211_FEXT_UAPSD)
323 #define IEEE80211_COM_UAPSD_DISABLE(_ic) ((_ic)->ic_flags_ext &= ~IEEE80211_FEXT_UAPSD)
324@@ -703,7 +711,7 @@ MALLOC_DECLARE(M_80211_VAP);
325 int ieee80211_ifattach(struct ieee80211com *);
326 void ieee80211_ifdetach(struct ieee80211com *);
327 int ieee80211_vap_setup(struct ieee80211com *, struct net_device *,
328- const char *, int, int);
329+ const char *, int, int, struct ieee80211vap *);
330 int ieee80211_vap_attach(struct ieee80211vap *, ifm_change_cb_t, ifm_stat_cb_t);
331 void ieee80211_vap_detach(struct ieee80211vap *);
332 void ieee80211_mark_dfs(struct ieee80211com *, struct ieee80211_channel *);
333--- a/net80211/ieee80211_wireless.c
334+++ b/net80211/ieee80211_wireless.c
335@@ -2190,7 +2190,7 @@ ieee80211_setupxr(struct ieee80211vap *v
336             ieee80211_scan_flush(ic); /* NB: could optimize */
337 
338             if (!(xrvap = ic->ic_vap_create(ic, name, IEEE80211_M_HOSTAP,
339- IEEE80211_VAP_XR | IEEE80211_CLONE_BSSID, dev)))
340+ IEEE80211_VAP_XR | IEEE80211_CLONE_BSSID, dev, NULL)))
341                 return;
342 
343             /* We use iv_xrvap to link to the parent VAP as well */
344@@ -2867,6 +2867,14 @@ ieee80211_ioctl_setparam(struct net_devi
345         else
346             vap->iv_minrateindex = 0;
347         break;
348+ case IEEE80211_PARAM_WDS_SEP:
349+ if (vap->iv_opmode != IEEE80211_M_HOSTAP)
350+ retv = -EINVAL;
351+ else if (value)
352+ vap->iv_flags_ext |= IEEE80211_FEXT_WDSSEP;
353+ else
354+ vap->iv_flags_ext &= ~IEEE80211_FEXT_WDSSEP;
355+ break;
356 #ifdef ATH_REVERSE_ENGINEERING
357     case IEEE80211_PARAM_DUMPREGS:
358         ieee80211_dump_registers(dev, info, w, extra);
359@@ -3223,6 +3231,9 @@ ieee80211_ioctl_getparam(struct net_devi
360     case IEEE80211_PARAM_MINRATE:
361         param[0] = vap->iv_minrateindex;
362         break;
363+ case IEEE80211_PARAM_WDS_SEP:
364+ param[0] = !!(vap->iv_flags_ext & IEEE80211_FEXT_WDSSEP);
365+ break;
366     default:
367         return -EOPNOTSUPP;
368     }
369@@ -3801,74 +3812,54 @@ ieee80211_ioctl_setmlme(struct net_devic
370     return 0;
371 }
372 
373+#define WDSNAME ".wds%d"
374 static int
375-ieee80211_ioctl_wdsmac(struct net_device *dev, struct iw_request_info *info,
376+ieee80211_ioctl_wdsaddmac(struct net_device *dev, struct iw_request_info *info,
377     void *w, char *extra)
378 {
379     struct ieee80211vap *vap = dev->priv;
380     struct sockaddr *sa = (struct sockaddr *)extra;
381+ struct ieee80211com *ic = vap->iv_ic;
382+ struct ieee80211vap *avp;
383+ char *name;
384 
385- if (!IEEE80211_ADDR_NULL(vap->wds_mac)) {
386- printk("%s: Failed to add WDS MAC: " MAC_FMT "\n", dev->name,
387- MAC_ADDR(sa->sa_data));
388- printk("%s: Device already has WDS mac address attached,"
389- " remove first\n", dev->name);
390- return -1;
391- }
392-
393- memcpy(vap->wds_mac, sa->sa_data, IEEE80211_ADDR_LEN);
394+ if (vap->iv_opmode != IEEE80211_M_HOSTAP)
395+ return -EINVAL;
396 
397- printk("%s: Added WDS MAC: " MAC_FMT "\n", dev->name,
398- MAC_ADDR(vap->wds_mac));
399+ name = kmalloc(strlen(vap->iv_dev->name) + sizeof(WDSNAME) + 1, GFP_KERNEL);
400+ if (!name)
401+ return -ENOMEM;
402 
403- if (IS_UP(vap->iv_dev)) {
404- /* Force us back to scan state to force us to go back through RUN
405- * state and create/pin the WDS peer node into memory. */
406- return ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
407- }
408+ strcpy(name, vap->iv_dev->name);
409+ strcat(name, WDSNAME);
410+ avp = ieee80211_create_vap(ic, name, ic->ic_dev, IEEE80211_M_WDS, 0, vap);
411+ kfree(name);
412+ if (!avp)
413+ return -ENOMEM;
414 
415+ memcpy(avp->wds_mac, sa->sa_data, IEEE80211_ADDR_LEN);
416     return 0;
417 }
418+#undef WDSNAME
419 
420 static int
421-ieee80211_ioctl_wdsdelmac(struct net_device *dev, struct iw_request_info *info,
422+ieee80211_ioctl_wdssetmac(struct net_device *dev, struct iw_request_info *info,
423     void *w, char *extra)
424 {
425     struct ieee80211vap *vap = dev->priv;
426     struct sockaddr *sa = (struct sockaddr *)extra;
427- struct ieee80211com *ic = vap->iv_ic;
428- struct ieee80211_node *wds_ni;
429 
430- /* WDS Mac address filed already? */
431- if (IEEE80211_ADDR_NULL(vap->wds_mac))
432- return 0;
433+ if (vap->iv_opmode != IEEE80211_M_WDS)
434+ return -EINVAL;
435 
436- /* Compare suplied MAC address with WDS MAC of this interface
437- * remove when mac address is known
438- */
439- if (memcmp(vap->wds_mac, sa->sa_data, IEEE80211_ADDR_LEN) == 0) {
440- if (IS_UP(vap->iv_dev)) {
441- wds_ni = ieee80211_find_txnode(vap, vap->wds_mac);
442- if (wds_ni != NULL) {
443- /* Release reference created by find node */
444- ieee80211_unref_node(&wds_ni);
445- /* Release reference created by transition to RUN state,
446- * [pinning peer node into the table] */
447- ieee80211_unref_node(&wds_ni);
448- }
449- }
450- memset(vap->wds_mac, 0x00, IEEE80211_ADDR_LEN);
451- if (IS_UP(vap->iv_dev)) {
452- /* This leaves a dead WDS node, until started again */
453- return ic->ic_reset(ic->ic_dev);
454- }
455- return 0;
456+ memcpy(vap->wds_mac, sa->sa_data, IEEE80211_ADDR_LEN);
457+ if (IS_UP(vap->iv_dev)) {
458+ /* Force us back to scan state to force us to go back through RUN
459+ * state and create/pin the WDS peer node into memory. */
460+ return ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
461     }
462 
463- printk("%s: WDS MAC address " MAC_FMT " is not known by this interface\n",
464- dev->name, MAC_ADDR(sa->sa_data));
465-
466- return -1;
467+ return 0;
468 }
469 
470 /*
471@@ -4470,6 +4461,8 @@ get_sta_space(void *arg, struct ieee8021
472     struct ieee80211vap *vap = ni->ni_vap;
473     size_t ielen;
474 
475+ if (req->vap->iv_wdsnode && ni->ni_subif)
476+ vap = ni->ni_subif;
477     if (vap != req->vap && vap != req->vap->iv_xrvap) /* only entries for this vap */
478         return;
479     if ((vap->iv_opmode == IEEE80211_M_HOSTAP ||
480@@ -4489,6 +4482,8 @@ get_sta_info(void *arg, struct ieee80211
481     size_t ielen, len;
482     u_int8_t *cp;
483 
484+ if (req->vap->iv_wdsnode && ni->ni_subif)
485+ vap = ni->ni_subif;
486     if (vap != req->vap && vap != req->vap->iv_xrvap) /* only entries for this vap (or) xrvap */
487         return;
488     if ((vap->iv_opmode == IEEE80211_M_HOSTAP ||
489@@ -5391,8 +5386,8 @@ static const struct iw_priv_args ieee802
490       IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "kickmac"},
491     { IEEE80211_IOCTL_WDSADDMAC,
492       IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,"wds_add" },
493- { IEEE80211_IOCTL_WDSDELMAC,
494- IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,"wds_del" },
495+ { IEEE80211_IOCTL_WDSSETMAC,
496+ IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,"wds_set" },
497     { IEEE80211_IOCTL_SETCHANLIST,
498       IW_PRIV_TYPE_CHANLIST | IW_PRIV_SIZE_FIXED, 0,"setchanlist" },
499     { IEEE80211_IOCTL_GETCHANLIST,
500@@ -5790,6 +5785,10 @@ static const struct iw_priv_args ieee802
501      0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_minrate"},
502     { IEEE80211_IOCTL_SETSCANLIST,
503      IW_PRIV_TYPE_CHAR | 255, 0, "setscanlist"},
504+ { IEEE80211_PARAM_WDS_SEP,
505+ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wdssep"},
506+ { IEEE80211_PARAM_WDS_SEP,
507+ 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_wdssep"},
508 
509 #ifdef ATH_REVERSE_ENGINEERING
510     /*
511@@ -5884,8 +5883,8 @@ static const iw_handler ieee80211_priv_h
512 #endif
513     set_priv(IEEE80211_IOCTL_ADDMAC, ieee80211_ioctl_addmac),
514     set_priv(IEEE80211_IOCTL_DELMAC, ieee80211_ioctl_delmac),
515- set_priv(IEEE80211_IOCTL_WDSADDMAC, ieee80211_ioctl_wdsmac),
516- set_priv(IEEE80211_IOCTL_WDSDELMAC, ieee80211_ioctl_wdsdelmac),
517+ set_priv(IEEE80211_IOCTL_WDSADDMAC, ieee80211_ioctl_wdsaddmac),
518+ set_priv(IEEE80211_IOCTL_WDSSETMAC, ieee80211_ioctl_wdssetmac),
519     set_priv(IEEE80211_IOCTL_KICKMAC, ieee80211_ioctl_kickmac),
520     set_priv(IEEE80211_IOCTL_SETSCANLIST, ieee80211_ioctl_setscanlist),
521 #ifdef ATH_REVERSE_ENGINEERING
522@@ -5913,6 +5912,8 @@ static int
523 ieee80211_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
524 {
525     struct ieee80211vap *vap = dev->priv;
526+ struct ieee80211com *ic = vap->iv_ic;
527+ struct ieee80211_node *ni;
528 
529     switch (cmd) {
530     case SIOCG80211STATS:
531@@ -5921,8 +5922,20 @@ ieee80211_ioctl(struct net_device *dev,
532     case SIOC80211IFDESTROY:
533         if (!capable(CAP_NET_ADMIN))
534             return -EPERM;
535+ /* drop all node subifs */
536+ TAILQ_FOREACH(ni, &ic->ic_sta.nt_node, ni_list) {
537+ struct ieee80211vap *avp = ni->ni_subif;
538+
539+ if (ni->ni_vap != vap)
540+ continue;
541+ if (!avp)
542+ continue;
543+ ni->ni_subif = NULL;
544+ ieee80211_stop(avp->iv_dev);
545+ ic->ic_vap_delete(avp);
546+ }
547         ieee80211_stop(vap->iv_dev); /* force state before cleanup */
548- vap->iv_ic->ic_vap_delete(vap);
549+ ic->ic_vap_delete(vap);
550         return 0;
551     case IEEE80211_IOCTL_GETKEY:
552         return ieee80211_ioctl_getkey(dev, (struct iwreq *) ifr);
553@@ -5956,7 +5969,7 @@ ieee80211_ioctl_create_vap(struct ieee80
554 
555     strncpy(name, cp.icp_name, sizeof(name));
556 
557- vap = ieee80211_create_vap(ic, name, mdev, cp.icp_opmode, cp.icp_flags);
558+ vap = ieee80211_create_vap(ic, name, mdev, cp.icp_opmode, cp.icp_flags, NULL);
559     if (vap == NULL)
560         return -EIO;
561 
562@@ -5973,9 +5986,9 @@ EXPORT_SYMBOL(ieee80211_ioctl_create_vap
563  */
564 struct ieee80211vap*
565 ieee80211_create_vap(struct ieee80211com *ic, char *name,
566- struct net_device *mdev, int opmode, int opflags)
567+ struct net_device *mdev, int opmode, int opflags, struct ieee80211vap *master)
568 {
569- return ic->ic_vap_create(ic, name, opmode, opflags, mdev);
570+ return ic->ic_vap_create(ic, name, opmode, opflags, mdev, master);
571 }
572 EXPORT_SYMBOL(ieee80211_create_vap);
573 
574--- a/net80211/ieee80211_input.c
575+++ b/net80211/ieee80211_input.c
576@@ -199,8 +199,10 @@ ieee80211_input(struct ieee80211vap * va
577 {
578 #define HAS_SEQ(type) ((type & 0x4) == 0)
579     struct ieee80211_node * ni = ni_or_null;
580- struct ieee80211com *ic = vap->iv_ic;
581- struct net_device *dev = vap->iv_dev;
582+ struct ieee80211com *ic;
583+ struct net_device *dev;
584+ struct ieee80211_node *ni_wds = NULL;
585+ struct net_device_stats *stats;
586     struct ieee80211_frame *wh;
587     struct ieee80211_key *key;
588     struct ether_header *eh;
589@@ -212,6 +214,19 @@ ieee80211_input(struct ieee80211vap * va
590     u_int8_t *bssid;
591     u_int16_t rxseq;
592 
593+ type = -1; /* undefined */
594+
595+ if (!vap)
596+ goto out;
597+
598+ ic = vap->iv_ic;
599+ if (!ic)
600+ goto out;
601+
602+ dev = vap->iv_dev;
603+ if (!dev)
604+ goto out;
605+
606     /* initialize ni as in the previous API */
607     if (ni_or_null == NULL) {
608                /* This function does not 'own' vap->iv_bss, so we cannot
609@@ -227,7 +242,6 @@ ieee80211_input(struct ieee80211vap * va
610 
611     /* XXX adjust device in sk_buff? */
612 
613- type = -1; /* undefined */
614     /*
615      * In monitor mode, send everything directly to bpf.
616      * Also do not process frames w/o i_addr2 any further.
617@@ -434,7 +448,7 @@ ieee80211_input(struct ieee80211vap * va
618 
619     switch (type) {
620     case IEEE80211_FC0_TYPE_DATA:
621- hdrspace = ieee80211_hdrspace(ic, wh);
622+ hdrspace = ieee80211_hdrsize(wh);
623         if (skb->len < hdrspace) {
624             IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
625                 wh, "data", "too short: len %u, expecting %u",
626@@ -444,16 +458,24 @@ ieee80211_input(struct ieee80211vap * va
627         }
628         switch (vap->iv_opmode) {
629         case IEEE80211_M_STA:
630- if ((dir != IEEE80211_FC1_DIR_FROMDS) &&
631- (!((vap->iv_flags_ext & IEEE80211_FEXT_WDS) &&
632- (dir == IEEE80211_FC1_DIR_DSTODS)))) {
633+ switch(dir) {
634+ case IEEE80211_FC1_DIR_FROMDS:
635+ break;
636+ case IEEE80211_FC1_DIR_DSTODS:
637+ if (vap->iv_flags_ext & IEEE80211_FEXT_WDS)
638+ break;
639+ default:
640                 IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
641                     wh, "data", "invalid dir 0x%x", dir);
642                 vap->iv_stats.is_rx_wrongdir++;
643                 goto out;
644             }
645 
646- if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
647+ if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
648+ /* ignore 3-addr mcast if we're WDS STA */
649+ if (vap->iv_flags_ext & IEEE80211_FEXT_WDS)
650+ goto out;
651+
652                 /* Discard multicast if IFF_MULTICAST not set */
653                 if ((0 != memcmp(wh->i_addr3, dev->broadcast, ETH_ALEN)) &&
654                     (0 == (dev->flags & IFF_MULTICAST))) {
655@@ -481,24 +503,10 @@ ieee80211_input(struct ieee80211vap * va
656                     vap->iv_stats.is_rx_mcastecho++;
657                     goto out;
658                 }
659- /*
660- * if it is brodcasted by me on behalf of
661- * a station behind me, drop it.
662- */
663- if (vap->iv_flags_ext & IEEE80211_FEXT_WDS) {
664- struct ieee80211_node_table *nt;
665- struct ieee80211_node *ni_wds;
666- nt = &ic->ic_sta;
667- ni_wds = ieee80211_find_wds_node(nt, wh->i_addr3);
668- if (ni_wds) {
669- ieee80211_unref_node(&ni_wds);
670- IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
671- wh, NULL, "%s",
672- "multicast echo originated from node behind me");
673- vap->iv_stats.is_rx_mcastecho++;
674- goto out;
675- }
676- }
677+ } else {
678+ /* Same BSSID, but not meant for us to receive */
679+ if (!IEEE80211_ADDR_EQ(wh->i_addr1, vap->iv_myaddr))
680+ goto out;
681             }
682             break;
683         case IEEE80211_M_IBSS:
684@@ -540,16 +548,28 @@ ieee80211_input(struct ieee80211vap * va
685                 vap->iv_stats.is_rx_notassoc++;
686                 goto err;
687             }
688+
689             /*
690              * If we're a 4 address packet, make sure we have an entry in
691              * the node table for the packet source address (addr4).
692              * If not, add one.
693              */
694+ /* check for wds link first */
695+ if ((dir == IEEE80211_FC1_DIR_DSTODS) && !ni->ni_subif) {
696+ if (vap->iv_flags_ext & IEEE80211_FEXT_WDSSEP) {
697+ ieee80211_wds_addif(ni);
698+ /* we must drop frames here until the interface has
699+ * been fully separated, otherwise a bridge might get
700+ * confused */
701+ goto err;
702+ }
703+ }
704+
705             /* XXX: Useless node mgmt API; make better */
706- if (dir == IEEE80211_FC1_DIR_DSTODS) {
707- struct ieee80211_node_table *nt;
708+ if ((dir == IEEE80211_FC1_DIR_DSTODS) && !vap->iv_wdsnode &&
709+ !ni_wds && !ni->ni_subif) {
710+ struct ieee80211_node_table *nt = &ic->ic_sta;
711                 struct ieee80211_frame_addr4 *wh4;
712- struct ieee80211_node *ni_wds;
713 
714                 if (!(vap->iv_flags_ext & IEEE80211_FEXT_WDS)) {
715                     IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT,
716@@ -557,7 +577,6 @@ ieee80211_input(struct ieee80211vap * va
717                     goto err;
718                 }
719                 wh4 = (struct ieee80211_frame_addr4 *)skb->data;
720- nt = &ic->ic_sta;
721                 ni_wds = ieee80211_find_wds_node(nt, wh4->i_addr4);
722                 /* Last call increments ref count if !NULL */
723                 if ((ni_wds != NULL) && (ni_wds != ni)) {
724@@ -608,6 +627,11 @@ ieee80211_input(struct ieee80211vap * va
725             goto out;
726         }
727 
728+ /* check if there is any data left */
729+ hdrspace = ieee80211_hdrspace(ic, wh);
730+ if (skb->len < hdrspace)
731+ goto out;
732+
733         /*
734          * Handle privacy requirements. Note that we
735          * must not be preempted from here until after
736@@ -680,8 +704,12 @@ ieee80211_input(struct ieee80211vap * va
737         if (! accept_data_frame(vap, ni, key, skb, eh))
738             goto out;
739 
740- vap->iv_devstats.rx_packets++;
741- vap->iv_devstats.rx_bytes += skb->len;
742+ if (ni->ni_subif && ((eh)->ether_type != __constant_htons(ETHERTYPE_PAE)))
743+ stats = &ni->ni_subif->iv_devstats;
744+ else
745+ stats = &vap->iv_devstats;
746+ stats->rx_packets++;
747+ stats->rx_bytes += skb->len;
748         IEEE80211_NODE_STAT(ni, rx_data);
749         IEEE80211_NODE_STAT_ADD(ni, rx_bytes, skb->len);
750         ic->ic_lastdata = jiffies;
751@@ -1114,6 +1142,18 @@ ieee80211_deliver_data(struct ieee80211_
752         dev = vap->iv_xrvap->iv_dev;
753 #endif
754 
755+ /* if the node has a wds subif, move data frames there,
756+ * but keep EAP traffic on the master */
757+ if (ni->ni_subif && ((eh)->ether_type != __constant_htons(ETHERTYPE_PAE))) {
758+ if (ni->ni_vap == ni->ni_subif) {
759+ ieee80211_dev_kfree_skb(&skb);
760+ return;
761+ } else {
762+ vap = ni->ni_subif;
763+ dev = vap->iv_dev;
764+ }
765+ }
766+
767     /* perform as a bridge within the vap */
768     /* XXX intra-vap bridging only */
769     if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
770@@ -1139,7 +1179,16 @@ ieee80211_deliver_data(struct ieee80211_
771             if (ni1 != NULL) {
772                 if (ni1->ni_vap == vap &&
773                     ieee80211_node_is_authorized(ni1) &&
774+ !ni1->ni_subif &&
775                     ni1 != vap->iv_bss) {
776+
777+ /* tried to bridge to a subif, drop the packet */
778+ if (ni->ni_subif) {
779+ ieee80211_unref_node(&ni1);
780+ ieee80211_dev_kfree_skb(&skb);
781+ return;
782+ }
783+
784                     skb1 = skb;
785                     skb = NULL;
786                 }
787@@ -3084,8 +3133,7 @@ ieee80211_recv_mgmt(struct ieee80211vap
788             (vap->iv_opmode == IEEE80211_M_STA && ni->ni_associd) ||
789             (vap->iv_opmode == IEEE80211_M_IBSS) ||
790             ((subtype == IEEE80211_FC0_SUBTYPE_BEACON) &&
791- (vap->iv_opmode == IEEE80211_M_HOSTAP) &&
792- (ic->ic_protmode != IEEE80211_PROT_NONE)))) {
793+ (vap->iv_opmode == IEEE80211_M_HOSTAP)))) {
794             vap->iv_stats.is_rx_mgtdiscard++;
795             return;
796         }
797@@ -3471,13 +3519,56 @@ ieee80211_recv_mgmt(struct ieee80211vap
798          */
799         if (ic->ic_flags & IEEE80211_F_SCAN) {
800             ieee80211_add_scan(vap, &scan, wh, subtype, rssi, rtsf);
801- return;
802         }
803- if ((vap->iv_opmode == IEEE80211_M_IBSS) &&
804- (scan.capinfo & IEEE80211_CAPINFO_IBSS)) {
805+ /* NB: Behavior of WDS-Link and Ad-Hoc is very similar here:
806+ * When we receive a beacon that belongs to the AP that we're
807+ * connected to, use it to refresh the local node info.
808+ * If no node is found, go through the vap's wds link table
809+ * and try to find the sub-vap that is interested in this address
810+ */
811+ if (((vap->iv_opmode == IEEE80211_M_IBSS) &&
812+ (scan.capinfo & IEEE80211_CAPINFO_IBSS)) ||
813+ (((vap->iv_opmode == IEEE80211_M_HOSTAP) ||
814+ (vap->iv_opmode == IEEE80211_M_WDS)) &&
815+ (scan.capinfo & IEEE80211_CAPINFO_ESS))) {
816+ struct ieee80211vap *avp = NULL;
817+ int found = 0;
818+
819+ IEEE80211_LOCK_IRQ(vap->iv_ic);
820+ if (vap->iv_opmode == IEEE80211_M_HOSTAP) {
821+ TAILQ_FOREACH(avp, &vap->iv_wdslinks, iv_wdsnext) {
822+ if (!memcmp(avp->wds_mac, wh->i_addr2, IEEE80211_ADDR_LEN)) {
823+ if (avp->iv_state != IEEE80211_S_RUN)
824+ continue;
825+ if (!avp->iv_wdsnode)
826+ continue;
827+ found = 1;
828+ break;
829+ }
830+ }
831+ if (found)
832+ ni = ni_or_null = avp->iv_wdsnode;
833+ } else if ((vap->iv_opmode == IEEE80211_M_WDS) && vap->iv_wdsnode) {
834+ found = 1;
835+ ni = ni_or_null = vap->iv_wdsnode;
836+ }
837+ IEEE80211_UNLOCK_IRQ(vap->iv_ic);
838+
839+ if (!found)
840+ break;
841+
842             if (ni_or_null == NULL) {
843- /* Create a new entry in the neighbor table. */
844- ni = ieee80211_add_neighbor(vap, wh, &scan);
845+ if (avp) {
846+ IEEE80211_LOCK_IRQ(ic);
847+ ni = ieee80211_add_neighbor(avp, wh, &scan);
848+ /* force assoc */
849+ ni->ni_associd |= 0xc000;
850+ avp->iv_wdsnode = ieee80211_ref_node(ni);
851+ IEEE80211_UNLOCK_IRQ(ic);
852+ } else if (vap->iv_opmode == IEEE80211_M_IBSS) {
853+ /* Create a new entry in the neighbor table. */
854+ ni = ieee80211_add_neighbor(vap, wh, &scan);
855+ }
856             } else {
857                 /*
858                  * Copy data from beacon to neighbor table.
859@@ -3490,6 +3581,7 @@ ieee80211_recv_mgmt(struct ieee80211vap
860                 IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3);
861                 memcpy(ni->ni_tstamp.data, scan.tstamp,
862                     sizeof(ni->ni_tstamp));
863+ ni->ni_inact = ni->ni_inact_reload;
864                 ni->ni_intval =
865                     IEEE80211_BINTVAL_SANITISE(scan.bintval);
866                 ni->ni_capinfo = scan.capinfo;
867--- a/net80211/ieee80211_node.c
868+++ b/net80211/ieee80211_node.c
869@@ -47,6 +47,7 @@
870 #include <linux/netdevice.h>
871 #include <linux/etherdevice.h>
872 #include <linux/random.h>
873+#include <linux/rtnetlink.h>
874 
875 #include "if_media.h"
876 
877@@ -236,7 +237,11 @@ void
878 ieee80211_node_vdetach(struct ieee80211vap *vap)
879 {
880     struct ieee80211com *ic = vap->iv_ic;
881+ struct ieee80211_node *ni;
882 
883+ ni = vap->iv_wdsnode;
884+ if (ni)
885+ ni->ni_subif = NULL;
886     ieee80211_node_table_reset(&ic->ic_sta, vap);
887     if (vap->iv_bss != NULL) {
888         ieee80211_unref_node(&vap->iv_bss);
889@@ -309,7 +314,7 @@ ieee80211_create_ibss(struct ieee80211va
890     /* Check to see if we already have a node for this mac
891      * NB: we gain a node reference here
892      */
893- ni = ieee80211_find_node(&ic->ic_sta, vap->iv_myaddr);
894+ ni = ieee80211_find_txnode(vap, vap->iv_myaddr);
895     if (ni == NULL) {
896         ni = ieee80211_alloc_node_table(vap, vap->iv_myaddr);
897         IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
898@@ -831,12 +836,18 @@ node_table_leave_locked(struct ieee80211
899         LIST_REMOVE(ni, ni_hash);
900     }
901     ni->ni_table = NULL;
902+ if (ni->ni_vap->iv_wdsnode == ni) {
903+#ifdef IEEE80211_DEBUG_REFCNT
904+ ieee80211_unref_node_debug(&ni->ni_vap->iv_wdsnode, func, line);
905+#else
906+ ieee80211_unref_node(&ni->ni_vap->iv_wdsnode);
907+#endif
908+ }
909 #ifdef IEEE80211_DEBUG_REFCNT
910     ieee80211_unref_node_debug(&ni, func, line);
911 #else
912     ieee80211_unref_node(&ni);
913 #endif
914-
915 }
916 
917 /* This is overridden by ath_node_alloc in ath/if_ath.c, and so
918@@ -1134,6 +1145,65 @@ ieee80211_alloc_node(struct ieee80211vap
919     return ni;
920 }
921 
922+#define WDSIFNAME ".sta%d"
923+static void
924+ieee80211_wds_do_addif(struct work_struct *work)
925+{
926+ struct ieee80211_node *ni = container_of(work, struct ieee80211_node, ni_create);
927+ struct ieee80211vap *vap = ni->ni_vap;
928+ struct ieee80211com *ic = vap->iv_ic;
929+ struct ieee80211vap *avp = NULL;
930+ char *name;
931+
932+ rtnl_lock();
933+ /* did we get cancelled by the destroy call? */
934+ if (!ni->ni_subif)
935+ goto done;
936+
937+ ni->ni_subif = NULL;
938+ name = kmalloc(strlen(vap->iv_dev->name) + sizeof(WDSIFNAME) + 1, GFP_KERNEL);
939+ if (!name)
940+ goto done;
941+
942+ strcpy(name, vap->iv_dev->name);
943+ strcat(name, WDSIFNAME);
944+ avp = ieee80211_create_vap(ic, name, ic->ic_dev, IEEE80211_M_WDS, 0, vap);
945+ kfree(name);
946+ if (!avp)
947+ goto done;
948+
949+ memcpy(avp->wds_mac, ni->ni_bssid, IEEE80211_ADDR_LEN);
950+ avp->iv_wdsnode = ieee80211_ref_node(ni);
951+ ni->ni_subif = avp;
952+ ic->ic_subifs++;
953+
954+done:
955+ if (avp) {
956+ IEEE80211_VAPS_LOCK_IRQ(ic);
957+ avp->iv_newstate(vap, IEEE80211_S_RUN, -1);
958+ IEEE80211_VAPS_UNLOCK_IRQ(ic);
959+ }
960+ rtnl_unlock();
961+ ieee80211_unref_node(&ni);
962+}
963+#undef WDSIFNAME
964+
965+void ieee80211_wds_addif(struct ieee80211_node *ni)
966+{
967+ /* check if the node is split out already,
968+ * or if we're in progress of setting up a new interface already */
969+ if (ni->ni_subif)
970+ return;
971+
972+ if (!ni->ni_table)
973+ return;
974+
975+ ieee80211_ref_node(ni);
976+ ni->ni_subif = ni->ni_vap;
977+ IEEE80211_INIT_WORK(&ni->ni_create, ieee80211_wds_do_addif);
978+ schedule_work(&ni->ni_create);
979+}
980+
981 /* Add wds address to the node table */
982 int
983 #ifdef IEEE80211_DEBUG_REFCNT
984@@ -1553,22 +1623,39 @@ ieee80211_find_rxnode(struct ieee80211co
985     ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL)
986     struct ieee80211_node_table *nt;
987     struct ieee80211_node *ni;
988+ struct ieee80211vap *vap, *avp;
989+ const u_int8_t *addr;
990+
991+ if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/)
992+ addr = wh->i_addr1;
993+ else
994+ addr = wh->i_addr2;
995+
996+ if (IEEE80211_IS_MULTICAST(addr))
997+ return NULL;
998 
999     /* XXX check ic_bss first in station mode */
1000     /* XXX 4-address frames? */
1001     nt = &ic->ic_sta;
1002     IEEE80211_NODE_TABLE_LOCK_IRQ(nt);
1003- if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/)
1004-#ifdef IEEE80211_DEBUG_REFCNT
1005- ni = ieee80211_find_node_locked_debug(nt, wh->i_addr1, func, line);
1006-#else
1007- ni = ieee80211_find_node_locked(nt, wh->i_addr1);
1008-#endif
1009- else
1010+ if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) {
1011+ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
1012+ TAILQ_FOREACH(avp, &vap->iv_wdslinks, iv_wdsnext) {
1013+ if (!IEEE80211_ADDR_EQ(addr, avp->wds_mac))
1014+ continue;
1015+
1016+ if (avp->iv_wdsnode)
1017+ return ieee80211_ref_node(avp->iv_wdsnode);
1018+ else
1019+ return NULL;
1020+ }
1021+ }
1022+ }
1023+
1024 #ifdef IEEE80211_DEBUG_REFCNT
1025- ni = ieee80211_find_node_locked_debug(nt, wh->i_addr2, func, line);
1026+ ni = ieee80211_find_node_locked_debug(nt, addr, func, line);
1027 #else
1028- ni = ieee80211_find_node_locked(nt, wh->i_addr2);
1029+ ni = ieee80211_find_node_locked(nt, addr);
1030 #endif
1031     IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt);
1032 
1033@@ -1596,9 +1683,19 @@ ieee80211_find_txnode_debug(struct ieee8
1034 ieee80211_find_txnode(struct ieee80211vap *vap, const u_int8_t *mac)
1035 #endif
1036 {
1037+ struct ieee80211com *ic = vap->iv_ic;
1038     struct ieee80211_node_table *nt;
1039     struct ieee80211_node *ni = NULL;
1040 
1041+ IEEE80211_LOCK_IRQ(ic);
1042+ if (vap->iv_opmode == IEEE80211_M_WDS) {
1043+ if (vap->iv_wdsnode && (vap->iv_state == IEEE80211_S_RUN))
1044+ return ieee80211_ref_node(vap->iv_wdsnode);
1045+ else
1046+ return NULL;
1047+ }
1048+ IEEE80211_UNLOCK_IRQ(ic);
1049+
1050     /*
1051      * The destination address should be in the node table
1052      * unless we are operating in station mode or this is a
1053@@ -1669,6 +1766,11 @@ ieee80211_free_node(struct ieee80211_nod
1054 {
1055     struct ieee80211vap *vap = ni->ni_vap;
1056 
1057+ IEEE80211_LOCK_IRQ(ni->ni_ic);
1058+ if (vap && ni == vap->iv_wdsnode)
1059+ vap->iv_wdsnode = NULL;
1060+ IEEE80211_UNLOCK_IRQ(ni->ni_ic);
1061+
1062     atomic_dec(&ni->ni_ic->ic_node_counter);
1063     node_print_message(IEEE80211_MSG_NODE|IEEE80211_MSG_NODE_REF,
1064                1 /* show counter */,
1065@@ -1781,22 +1883,6 @@ restart:
1066             jiffies > ni->ni_rxfragstamp + HZ) {
1067             ieee80211_dev_kfree_skb(&ni->ni_rxfrag);
1068         }
1069- /*
1070- * Special case ourself; we may be idle for extended periods
1071- * of time and regardless reclaiming our state is wrong.
1072- * Special case a WDS link: it may be dead or idle, but it is
1073- * never ok to reclaim it, as this will block transmissions
1074- * and nobody will recreate the node when the WDS peer is
1075- * available again. */
1076- if ((ni == ni->ni_vap->iv_bss) ||
1077- (ni->ni_vap->iv_opmode == IEEE80211_M_WDS &&
1078- !memcmp(ni->ni_macaddr, ni->ni_vap->wds_mac, ETH_ALEN)))
1079- {
1080- /* NB: don't permit it to go negative */
1081- if (ni->ni_inact > 0)
1082- ni->ni_inact--;
1083- continue;
1084- }
1085         ni->ni_inact--;
1086         if (ni->ni_associd != 0 || isadhoc) {
1087             struct ieee80211vap *vap = ni->ni_vap;
1088@@ -2263,6 +2349,35 @@ ieee80211_node_leave_11g(struct ieee8021
1089     }
1090 }
1091 
1092+static void
1093+ieee80211_subif_destroy(struct work_struct *work)
1094+{
1095+ struct ieee80211_node *ni = container_of(work, struct ieee80211_node, ni_destroy);
1096+ struct ieee80211vap *vap;
1097+ struct ieee80211com *ic;
1098+
1099+ /* wait for full initialization before we start the teardown
1100+ * otherwise we could leak interfaces */
1101+ while (ni->ni_subif == ni->ni_vap)
1102+ schedule();
1103+
1104+ rtnl_lock();
1105+ vap = ni->ni_subif;
1106+
1107+ if (!vap)
1108+ goto done;
1109+
1110+ ic = vap->iv_ic;
1111+ ni->ni_subif = NULL;
1112+ ieee80211_stop(vap->iv_dev);
1113+ ic->ic_vap_delete(vap);
1114+ ic->ic_subifs--;
1115+
1116+done:
1117+ ieee80211_unref_node(&ni);
1118+ rtnl_unlock();
1119+}
1120+
1121 /*
1122  * Handle bookkeeping for a station/neighbor leaving
1123  * the bss when operating in ap or adhoc modes.
1124@@ -2279,6 +2394,12 @@ ieee80211_node_leave(struct ieee80211_no
1125             ni, "station with aid %d leaves (refcnt %u)",
1126             IEEE80211_NODE_AID(ni), atomic_read(&ni->ni_refcnt));
1127 
1128+ if (ni->ni_subif) {
1129+ ieee80211_ref_node(ni);
1130+ IEEE80211_INIT_WORK(&ni->ni_destroy, ieee80211_subif_destroy);
1131+ schedule_work(&ni->ni_destroy);
1132+ }
1133+
1134     /* From this point onwards we can no longer find the node,
1135      * so no more references are generated
1136      */
1137--- a/net80211/ieee80211_output.c
1138+++ b/net80211/ieee80211_output.c
1139@@ -246,15 +246,16 @@ ieee80211_hardstart(struct sk_buff *skb,
1140      * things like power save.
1141      */
1142     eh = (struct ether_header *)skb->data;
1143- if (vap->iv_opmode == IEEE80211_M_WDS)
1144- ni = ieee80211_find_txnode(vap, vap->wds_mac);
1145- else
1146- ni = ieee80211_find_txnode(vap, eh->ether_dhost);
1147+ ni = ieee80211_find_txnode(vap, eh->ether_dhost);
1148     if (ni == NULL) {
1149         /* NB: ieee80211_find_txnode does stat+msg */
1150         goto bad;
1151     }
1152 
1153+ if (ni->ni_subif && (vap != ni->ni_subif) &&
1154+ ((eh)->ether_type != __constant_htons(ETHERTYPE_PAE)))
1155+ goto bad;
1156+
1157     /* calculate priority so drivers can find the TX queue */
1158     if (ieee80211_classify(ni, skb)) {
1159         IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni,
1160@@ -334,20 +335,33 @@ void ieee80211_parent_queue_xmit(struct
1161  * constructing a frame as it sets i_fc[1]; other bits can
1162  * then be or'd in.
1163  */
1164-static void
1165+static struct ieee80211_frame *
1166 ieee80211_send_setup(struct ieee80211vap *vap,
1167     struct ieee80211_node *ni,
1168- struct ieee80211_frame *wh,
1169+ struct sk_buff *skb,
1170     int type,
1171     const u_int8_t sa[IEEE80211_ADDR_LEN],
1172     const u_int8_t da[IEEE80211_ADDR_LEN],
1173     const u_int8_t bssid[IEEE80211_ADDR_LEN])
1174 {
1175 #define WH4(wh) ((struct ieee80211_frame_addr4 *)wh)
1176+ struct ieee80211_frame *wh;
1177+ int len = sizeof(struct ieee80211_frame);
1178+ int opmode = vap->iv_opmode;
1179 
1180+ if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {
1181+ if ((opmode == IEEE80211_M_STA) &&
1182+ (vap->iv_flags_ext & IEEE80211_FEXT_WDS))
1183+ opmode = IEEE80211_M_WDS;
1184+
1185+ if (opmode == IEEE80211_M_WDS)
1186+ len = sizeof(struct ieee80211_frame_addr4);
1187+ }
1188+
1189+ wh = (struct ieee80211_frame *)skb_push(skb, len);
1190     wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type;
1191     if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) {
1192- switch (vap->iv_opmode) {
1193+ switch (opmode) {
1194         case IEEE80211_M_STA:
1195             wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
1196             IEEE80211_ADDR_COPY(wh->i_addr1, bssid);
1197@@ -389,6 +403,8 @@ ieee80211_send_setup(struct ieee80211vap
1198     *(__le16 *)&wh->i_seq[0] =
1199         htole16(ni->ni_txseqs[0] << IEEE80211_SEQ_SEQ_SHIFT);
1200     ni->ni_txseqs[0]++;
1201+
1202+ return wh;
1203 #undef WH4
1204 }
1205 
1206@@ -410,9 +426,7 @@ ieee80211_mgmt_output(struct ieee80211_n
1207 
1208     SKB_CB(skb)->ni = ni;
1209 
1210- wh = (struct ieee80211_frame *)
1211- skb_push(skb, sizeof(struct ieee80211_frame));
1212- ieee80211_send_setup(vap, ni, wh,
1213+ wh = ieee80211_send_setup(vap, ni, skb,
1214         IEEE80211_FC0_TYPE_MGT | type,
1215         vap->iv_myaddr, ni->ni_macaddr, vap->iv_bssid);
1216     /* XXX power management */
1217@@ -458,6 +472,9 @@ ieee80211_send_nulldata(struct ieee80211
1218     struct ieee80211_frame *wh;
1219     u_int8_t *frm;
1220 
1221+ if (ni->ni_subif)
1222+ vap = ni->ni_subif;
1223+
1224     skb = ieee80211_getmgtframe(&frm, 0);
1225     if (skb == NULL) {
1226         /* XXX debug msg */
1227@@ -466,9 +483,7 @@ ieee80211_send_nulldata(struct ieee80211
1228         return -ENOMEM;
1229     }
1230 
1231- wh = (struct ieee80211_frame *)
1232- skb_push(skb, sizeof(struct ieee80211_frame));
1233- ieee80211_send_setup(vap, ni, wh,
1234+ wh = ieee80211_send_setup(vap, ni, skb,
1235         IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA,
1236         vap->iv_myaddr, ni->ni_macaddr, vap->iv_bssid);
1237     /* NB: power management bit is never sent by an AP */
1238@@ -506,6 +521,7 @@ ieee80211_send_qosnulldata(struct ieee80
1239     struct sk_buff *skb;
1240     struct ieee80211_qosframe *qwh;
1241     u_int8_t *frm;
1242+ u_int8_t *i_qos;
1243     int tid;
1244 
1245     skb = ieee80211_getmgtframe(&frm, 2);
1246@@ -517,11 +533,12 @@ ieee80211_send_qosnulldata(struct ieee80
1247     SKB_CB(skb)->ni = ieee80211_ref_node(ni);
1248 
1249     skb->priority = ac;
1250- qwh = (struct ieee80211_qosframe *)skb_push(skb, sizeof(struct ieee80211_qosframe));
1251 
1252- qwh = (struct ieee80211_qosframe *)skb->data;
1253+ /* grab a pointer to QoS control and also compensate for the header length
1254+ * difference between QoS and non-QoS frame */
1255+ i_qos = skb_push(skb, sizeof(struct ieee80211_qosframe) - sizeof(struct ieee80211_frame));
1256 
1257- ieee80211_send_setup(vap, ni, (struct ieee80211_frame *)qwh,
1258+ qwh = (struct ieee80211_qosframe *) ieee80211_send_setup(vap, ni, skb,
1259         IEEE80211_FC0_TYPE_DATA,
1260         vap->iv_myaddr, /* SA */
1261         ni->ni_macaddr, /* DA */
1262@@ -535,10 +552,10 @@ ieee80211_send_qosnulldata(struct ieee80
1263 
1264     /* map from access class/queue to 11e header priority value */
1265     tid = WME_AC_TO_TID(ac);
1266- qwh->i_qos[0] = tid & IEEE80211_QOS_TID;
1267+ i_qos[0] = tid & IEEE80211_QOS_TID;
1268     if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy)
1269         qwh->i_qos[0] |= (1 << IEEE80211_QOS_ACKPOLICY_S) & IEEE80211_QOS_ACKPOLICY;
1270- qwh->i_qos[1] = 0;
1271+ i_qos[1] = 0;
1272 
1273     IEEE80211_NODE_STAT(ni, tx_data);
1274 
1275@@ -780,6 +797,8 @@ ieee80211_encap(struct ieee80211_node *n
1276         hdrsize = sizeof(struct ieee80211_frame);
1277 
1278     SKB_CB(skb)->auth_pkt = (eh.ether_type == __constant_htons(ETHERTYPE_PAE));
1279+ if (ni->ni_subif)
1280+ vap = ni->ni_subif;
1281 
1282     switch (vap->iv_opmode) {
1283     case IEEE80211_M_IBSS:
1284@@ -788,7 +807,7 @@ ieee80211_encap(struct ieee80211_node *n
1285         break;
1286     case IEEE80211_M_WDS:
1287         use4addr = 1;
1288- ismulticast = IEEE80211_IS_MULTICAST(ni->ni_macaddr);
1289+ ismulticast = 0;
1290         break;
1291     case IEEE80211_M_HOSTAP:
1292         if (!IEEE80211_IS_MULTICAST(eh.ether_dhost) &&
1293@@ -799,20 +818,9 @@ ieee80211_encap(struct ieee80211_node *n
1294             ismulticast = IEEE80211_IS_MULTICAST(eh.ether_dhost);
1295         break;
1296     case IEEE80211_M_STA:
1297- if ((vap->iv_flags_ext & IEEE80211_FEXT_WDS) &&
1298- !IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) {
1299+ if (vap->iv_flags_ext & IEEE80211_FEXT_WDS) {
1300             use4addr = 1;
1301- ismulticast = IEEE80211_IS_MULTICAST(ni->ni_macaddr);
1302- /* Add a WDS entry to the station VAP */
1303- if (IEEE80211_IS_MULTICAST(eh.ether_dhost)) {
1304- struct ieee80211_node_table *nt = &ic->ic_sta;
1305- struct ieee80211_node *ni_wds
1306- = ieee80211_find_wds_node(nt, eh.ether_shost);
1307- if (ni_wds)
1308- ieee80211_unref_node(&ni_wds);
1309- else
1310- ieee80211_add_wds_addr(nt, ni, eh.ether_shost, 0);
1311- }
1312+ ismulticast = 0;
1313         } else
1314             ismulticast = IEEE80211_IS_MULTICAST(vap->iv_bssid);
1315         break;
1316@@ -973,7 +981,7 @@ ieee80211_encap(struct ieee80211_node *n
1317             break;
1318         case IEEE80211_M_WDS:
1319             wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS;
1320- IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
1321+ IEEE80211_ADDR_COPY(wh->i_addr1, vap->wds_mac);
1322             IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
1323             IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
1324             IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost);
1325@@ -1683,9 +1691,7 @@ ieee80211_send_probereq(struct ieee80211
1326 
1327     SKB_CB(skb)->ni = ieee80211_ref_node(ni);
1328 
1329- wh = (struct ieee80211_frame *)
1330- skb_push(skb, sizeof(struct ieee80211_frame));
1331- ieee80211_send_setup(vap, ni, wh,
1332+ wh = ieee80211_send_setup(vap, ni, skb,
1333         IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ,
1334         sa, da, bssid);
1335     /* XXX power management? */
1336--- a/tools/athkey.c
1337+++ b/tools/athkey.c
1338@@ -118,7 +118,7 @@ set80211priv(const char *dev, int op, vo
1339                 IOCTL_ERR(IEEE80211_IOCTL_ADDMAC),
1340                 IOCTL_ERR(IEEE80211_IOCTL_DELMAC),
1341                 IOCTL_ERR(IEEE80211_IOCTL_WDSADDMAC),
1342- IOCTL_ERR(IEEE80211_IOCTL_WDSDELMAC),
1343+ IOCTL_ERR(IEEE80211_IOCTL_WDSSETMAC),
1344                 IOCTL_ERR(IEEE80211_IOCTL_READREG),
1345                 IOCTL_ERR(IEEE80211_IOCTL_WRITEREG),
1346             };
1347--- a/tools/athchans.c
1348+++ b/tools/athchans.c
1349@@ -118,7 +118,7 @@ set80211priv(const char *dev, int op, vo
1350                 IOCTL_ERR(IEEE80211_IOCTL_ADDMAC),
1351                 IOCTL_ERR(IEEE80211_IOCTL_DELMAC),
1352                 IOCTL_ERR(IEEE80211_IOCTL_WDSADDMAC),
1353- IOCTL_ERR(IEEE80211_IOCTL_WDSDELMAC),
1354+ IOCTL_ERR(IEEE80211_IOCTL_WDSSETMAC),
1355                 IOCTL_ERR(IEEE80211_IOCTL_READREG),
1356                 IOCTL_ERR(IEEE80211_IOCTL_WRITEREG),
1357             };
1358--- a/tools/wlanconfig.c
1359+++ b/tools/wlanconfig.c
1360@@ -968,7 +968,7 @@ do80211priv(struct iwreq *iwr, const cha
1361             IOCTL_ERR(IEEE80211_IOCTL_ADDMAC),
1362             IOCTL_ERR(IEEE80211_IOCTL_DELMAC),
1363             IOCTL_ERR(IEEE80211_IOCTL_WDSADDMAC),
1364- IOCTL_ERR(IEEE80211_IOCTL_WDSDELMAC),
1365+ IOCTL_ERR(IEEE80211_IOCTL_WDSSETMAC),
1366             IOCTL_ERR(IEEE80211_IOCTL_READREG),
1367             IOCTL_ERR(IEEE80211_IOCTL_WRITEREG),
1368         };
1369--- a/net80211/ieee80211_proto.c
1370+++ b/net80211/ieee80211_proto.c
1371@@ -979,6 +979,12 @@ ieee80211_init(struct net_device *dev, i
1372         "start running (state=%d)\n", vap->iv_state);
1373 
1374 
1375+ if (vap->iv_master && vap->iv_master->iv_state == IEEE80211_S_INIT) {
1376+ int ret = ieee80211_init(vap->iv_master->iv_dev, forcescan);
1377+ if (ret < 0)
1378+ return ret;
1379+ }
1380+
1381     if ((dev->flags & IFF_RUNNING) == 0) {
1382         if (ic->ic_nopened++ == 0 &&
1383             (parent->flags & IFF_RUNNING) == 0)
1384@@ -1081,6 +1087,8 @@ ieee80211_init(struct net_device *dev, i
1385 int
1386 ieee80211_open(struct net_device *dev)
1387 {
1388+ struct ieee80211vap *vap = dev->priv;
1389+
1390     return ieee80211_init(dev, 0);
1391 }
1392 
1393@@ -1090,7 +1098,7 @@ ieee80211_open(struct net_device *dev)
1394 void
1395 ieee80211_start_running(struct ieee80211com *ic)
1396 {
1397- struct ieee80211vap *vap;
1398+ struct ieee80211vap *vap, *avp;
1399     struct net_device *dev;
1400 
1401     /* XXX locking */
1402@@ -1099,6 +1107,16 @@ ieee80211_start_running(struct ieee80211
1403         /* NB: avoid recursion */
1404         if ((dev->flags & IFF_UP) && !(dev->flags & IFF_RUNNING))
1405             ieee80211_open(dev);
1406+
1407+ TAILQ_FOREACH(avp, &vap->iv_wdslinks, iv_wdsnext) {
1408+ if (avp->iv_wdsnode && avp->iv_wdsnode->ni_subif == avp)
1409+ continue;
1410+
1411+ dev = avp->iv_dev;
1412+ /* NB: avoid recursion */
1413+ if ((dev->flags & IFF_UP) && !(dev->flags & IFF_RUNNING))
1414+ ieee80211_open(dev);
1415+ }
1416     }
1417 }
1418 EXPORT_SYMBOL(ieee80211_start_running);
1419@@ -1116,11 +1134,43 @@ ieee80211_stop(struct net_device *dev)
1420     struct ieee80211vap *vap = dev->priv;
1421     struct ieee80211com *ic = vap->iv_ic;
1422     struct net_device *parent = ic->ic_dev;
1423+ struct ieee80211_node *tni, *ni;
1424+ struct ieee80211vap *avp;
1425 
1426     IEEE80211_DPRINTF(vap,
1427         IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG,
1428         "%s\n", "stop running");
1429 
1430+ if (vap->iv_wdsnode && !vap->iv_wdsnode->ni_subif)
1431+ ieee80211_unref_node(&vap->iv_wdsnode);
1432+
1433+ /* stop wds interfaces */
1434+ TAILQ_FOREACH(avp, &vap->iv_wdslinks, iv_next) {
1435+ if (avp->iv_state != IEEE80211_S_INIT)
1436+ ieee80211_stop(avp->iv_dev);
1437+ }
1438+
1439+ /* get rid of all wds nodes while we're still locked */
1440+ do {
1441+ ni = NULL;
1442+
1443+ IEEE80211_NODE_TABLE_LOCK_IRQ(&ic->ic_sta);
1444+ TAILQ_FOREACH(tni, &ic->ic_sta.nt_node, ni_list) {
1445+ if (tni->ni_vap != vap)
1446+ continue;
1447+ if (!tni->ni_subif)
1448+ continue;
1449+ ni = tni;
1450+ break;
1451+ }
1452+ IEEE80211_NODE_TABLE_UNLOCK_IRQ(&ic->ic_sta);
1453+
1454+ if (!ni)
1455+ break;
1456+
1457+ ieee80211_node_leave(ni);
1458+ } while (1);
1459+
1460     ieee80211_new_state(vap, IEEE80211_S_INIT, -1);
1461     if (dev->flags & IFF_RUNNING) {
1462         dev->flags &= ~IFF_RUNNING; /* mark us stopped */
1463@@ -1148,7 +1198,7 @@ EXPORT_SYMBOL(ieee80211_stop);
1464 void
1465 ieee80211_stop_running(struct ieee80211com *ic)
1466 {
1467- struct ieee80211vap *vap;
1468+ struct ieee80211vap *vap, *avp;
1469     struct net_device *dev;
1470 
1471     /* XXX locking */
1472@@ -1156,6 +1206,12 @@ ieee80211_stop_running(struct ieee80211c
1473         dev = vap->iv_dev;
1474         if (dev->flags & IFF_RUNNING) /* NB: avoid recursion */
1475             ieee80211_stop(dev);
1476+
1477+ TAILQ_FOREACH(avp, &vap->iv_wdslinks, iv_wdsnext) {
1478+ dev = avp->iv_dev;
1479+ if (dev->flags & IFF_RUNNING) /* NB: avoid recursion */
1480+ ieee80211_stop(dev);
1481+ }
1482     }
1483 }
1484 EXPORT_SYMBOL(ieee80211_stop_running);
1485@@ -1342,9 +1398,9 @@ ieee80211_new_state(struct ieee80211vap
1486     struct ieee80211com *ic = vap->iv_ic;
1487     int rc;
1488 
1489- IEEE80211_VAPS_LOCK_BH(ic);
1490+ IEEE80211_VAPS_LOCK_IRQ(ic);
1491     rc = vap->iv_newstate(vap, nstate, arg);
1492- IEEE80211_VAPS_UNLOCK_BH(ic);
1493+ IEEE80211_VAPS_UNLOCK_IRQ(ic);
1494     return rc;
1495 }
1496 
1497@@ -1557,57 +1613,12 @@ __ieee80211_newstate(struct ieee80211vap
1498         switch (ostate) {
1499         case IEEE80211_S_INIT:
1500             if (vap->iv_opmode == IEEE80211_M_MONITOR ||
1501- vap->iv_opmode == IEEE80211_M_WDS ||
1502                 vap->iv_opmode == IEEE80211_M_HOSTAP) {
1503                 /*
1504                  * Already have a channel; bypass the
1505                  * scan and startup immediately.
1506                  */
1507                 ieee80211_create_ibss(vap, ic->ic_curchan);
1508-
1509- /* In WDS mode, allocate and initialize peer node. */
1510- if (vap->iv_opmode == IEEE80211_M_WDS) {
1511- /* XXX: This is horribly non-atomic. */
1512- struct ieee80211_node *wds_ni =
1513- ieee80211_find_node(&ic->ic_sta,
1514- vap->wds_mac);
1515-
1516- if (wds_ni == NULL) {
1517- wds_ni = ieee80211_alloc_node_table(
1518- vap,
1519- vap->wds_mac);
1520- if (wds_ni != NULL) {
1521- ieee80211_add_wds_addr(
1522- &ic->ic_sta,
1523- wds_ni,
1524- vap->wds_mac,
1525- 1);
1526- ieee80211_ref_node(wds_ni); /* pin in memory */
1527- }
1528- else
1529- IEEE80211_DPRINTF(
1530- vap,
1531- IEEE80211_MSG_NODE,
1532- "%s: Unable to "
1533- "allocate node for "
1534- "WDS: " MAC_FMT "\n",
1535- __func__,
1536- MAC_ADDR(
1537- vap->wds_mac)
1538- );
1539- }
1540-
1541- if (wds_ni != NULL) {
1542- ieee80211_node_authorize(wds_ni);
1543- wds_ni->ni_chan =
1544- vap->iv_bss->ni_chan;
1545- wds_ni->ni_capinfo =
1546- ni->ni_capinfo;
1547- wds_ni->ni_associd = 1;
1548- wds_ni->ni_ath_flags =
1549- vap->iv_ath_cap;
1550- }
1551- }
1552                 break;
1553             }
1554             /* fall thru... */
1555@@ -1675,6 +1686,7 @@ __ieee80211_newstate(struct ieee80211vap
1556          */
1557         if (ni->ni_authmode != IEEE80211_AUTH_8021X)
1558             ieee80211_node_authorize(ni);
1559+
1560 #ifdef ATH_SUPERG_XR
1561         /*
1562          * fire a timer to bring up XR vap if configured.
1563@@ -1808,6 +1820,11 @@ ieee80211_newstate(struct ieee80211vap *
1564               ieee80211_state_name[dstate]);
1565 
1566     ieee80211_update_link_status(vap, nstate, ostate);
1567+
1568+ if ((nstate != IEEE80211_S_RUN) && vap->iv_wdsnode &&
1569+ !vap->iv_wdsnode->ni_subif)
1570+ ieee80211_unref_node(&vap->iv_wdsnode);
1571+
1572     switch (nstate) {
1573     case IEEE80211_S_AUTH:
1574     case IEEE80211_S_ASSOC:
1575@@ -1930,8 +1947,15 @@ ieee80211_newstate(struct ieee80211vap *
1576         if (ostate == IEEE80211_S_SCAN ||
1577             ostate == IEEE80211_S_AUTH ||
1578             ostate == IEEE80211_S_ASSOC) {
1579+
1580             /* Transition (S_SCAN|S_AUTH|S_ASSOC) -> S_RUN */
1581             __ieee80211_newstate(vap, nstate, arg);
1582+
1583+ /* if we're in wds, let the ap know that we're doing this */
1584+ if ((vap->iv_opmode == IEEE80211_M_STA) &&
1585+ (vap->iv_flags_ext & IEEE80211_FEXT_WDS))
1586+ ieee80211_send_nulldata(ieee80211_ref_node(vap->iv_bss));
1587+
1588             /* Then bring up all other vaps pending on the scan */
1589             dstate = get_dominant_state(ic);
1590             if (dstate == IEEE80211_S_RUN) {
1591--- a/ath/if_athvar.h
1592+++ b/ath/if_athvar.h
1593@@ -79,28 +79,6 @@ typedef void *TQUEUE_ARG;
1594 #define tasklet_enable(t) do { (void) t; local_bh_enable(); } while (0)
1595 #endif /* !DECLARE_TASKLET */
1596 
1597-#include <linux/sched.h>
1598-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,41)
1599-#include <linux/tqueue.h>
1600-#define work_struct tq_struct
1601-#define schedule_work(t) schedule_task((t))
1602-#define flush_scheduled_work() flush_scheduled_tasks()
1603-#define ATH_INIT_WORK(t, f) do { \
1604- memset((t), 0, sizeof(struct tq_struct)); \
1605- (t)->routine = (void (*)(void*)) (f); \
1606- (t)->data=(void *) (t); \
1607-} while (0)
1608-#else
1609-#include <linux/workqueue.h>
1610-
1611-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
1612-#define ATH_INIT_WORK(_t, _f) INIT_WORK((_t), (void (*)(void *))(_f), (_t));
1613-#else
1614-#define ATH_INIT_WORK(_t, _f) INIT_WORK((_t), (_f));
1615-#endif
1616-
1617-#endif /* KERNEL_VERSION < 2.5.41 */
1618-
1619 /*
1620  * Guess how the interrupt handler should work.
1621  */
1622--- a/net80211/ieee80211_linux.c
1623+++ b/net80211/ieee80211_linux.c
1624@@ -145,7 +145,7 @@ ieee80211_getmgtframe(u_int8_t **frm, u_
1625     struct sk_buff *skb;
1626     u_int len;
1627 
1628- len = roundup(sizeof(struct ieee80211_frame) + pktlen, 4);
1629+ len = roundup(sizeof(struct ieee80211_frame_addr4) + pktlen, 4);
1630 #ifdef IEEE80211_DEBUG_REFCNT
1631     skb = ieee80211_dev_alloc_skb_debug(len + align - 1, func, line);
1632 #else
1633@@ -161,7 +161,7 @@ ieee80211_getmgtframe(u_int8_t **frm, u_
1634         SKB_CB(skb)->flags = 0;
1635         SKB_CB(skb)->next = NULL;
1636 
1637- skb_reserve(skb, sizeof(struct ieee80211_frame));
1638+ skb_reserve(skb, sizeof(struct ieee80211_frame_addr4));
1639         *frm = skb_put(skb, pktlen);
1640     }
1641     return skb;
1642--- a/net80211/ieee80211_node.h
1643+++ b/net80211/ieee80211_node.h
1644@@ -92,11 +92,13 @@ struct ath_softc;
1645  * the ieee80211com structure.
1646  */
1647 struct ieee80211_node {
1648- struct ieee80211vap *ni_vap;
1649+ struct ieee80211vap *ni_vap, *ni_subif;
1650     struct ieee80211com *ni_ic;
1651     struct ieee80211_node_table *ni_table;
1652     TAILQ_ENTRY(ieee80211_node) ni_list;
1653     LIST_ENTRY(ieee80211_node) ni_hash;
1654+ struct work_struct ni_create; /* task for creating a subif */
1655+ struct work_struct ni_destroy; /* task for destroying a subif */
1656     atomic_t ni_refcnt;
1657     u_int ni_scangen; /* gen# for timeout scan */
1658     u_int8_t ni_authmode; /* authentication algorithm */
1659@@ -430,5 +432,6 @@ void ieee80211_node_join(struct ieee8021
1660 void ieee80211_node_leave(struct ieee80211_node *);
1661 u_int8_t ieee80211_getrssi(struct ieee80211com *);
1662 int32_t ieee80211_get_node_count(struct ieee80211com *);
1663+void ieee80211_wds_addif(struct ieee80211_node *ni);
1664 #endif /* _NET80211_IEEE80211_NODE_H_ */
1665 
1666

Archive Download this file



interactive