From 6d19fadd654def93d47609c45944264eaa981d65 Mon Sep 17 00:00:00 2001 From: nbd Date: Wed, 30 Jul 2008 04:45:24 +0000 Subject: madwifi: wds updates - refactor wds code - add interface for separating individual wds stations from the master interface - add some queueing fixes for packets passing through virtual interfaces git-svn-id: svn://svn.openwrt.org/openwrt/trunk@12003 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- package/madwifi/patches/370-wdsvap.patch | 706 +++++++++++++++++++++++++++++++ 1 file changed, 706 insertions(+) create mode 100644 package/madwifi/patches/370-wdsvap.patch (limited to 'package/madwifi/patches/370-wdsvap.patch') diff --git a/package/madwifi/patches/370-wdsvap.patch b/package/madwifi/patches/370-wdsvap.patch new file mode 100644 index 000000000..ee0a2de5b --- /dev/null +++ b/package/madwifi/patches/370-wdsvap.patch @@ -0,0 +1,706 @@ +--- a/ath/if_ath.c ++++ b/ath/if_ath.c +@@ -124,7 +124,7 @@ + }; + + static struct ieee80211vap *ath_vap_create(struct ieee80211com *, +- const char *, int, int, struct net_device *); ++ const char *, int, int, struct net_device *, struct ieee80211vap *); + static void ath_vap_delete(struct ieee80211vap *); + static int ath_init(struct net_device *); + static int ath_set_ack_bitrate(struct ath_softc *, int); +@@ -1123,8 +1123,6 @@ + autocreatemode = IEEE80211_M_IBSS; + else if (!strcmp(autocreate, "ahdemo")) + autocreatemode = IEEE80211_M_AHDEMO; +- else if (!strcmp(autocreate, "wds")) +- autocreatemode = IEEE80211_M_WDS; + else if (!strcmp(autocreate, "monitor")) + autocreatemode = IEEE80211_M_MONITOR; + else { +@@ -1137,7 +1135,7 @@ + if (autocreatemode != -1) { + rtnl_lock(); + vap = ieee80211_create_vap(ic, "ath%d", dev, +- autocreatemode, 0); ++ autocreatemode, 0, NULL); + rtnl_unlock(); + if (vap == NULL) + EPRINTF(sc, "Autocreation of %s VAP failed.", autocreate); +@@ -1230,14 +1228,14 @@ + + static struct ieee80211vap * + ath_vap_create(struct ieee80211com *ic, const char *name, +- int opmode, int flags, struct net_device *mdev) ++ int opmode, int flags, struct net_device *mdev, struct ieee80211vap *master) + { + struct ath_softc *sc = ic->ic_dev->priv; + struct ath_hal *ah = sc->sc_ah; + struct net_device *dev; + struct ath_vap *avp; + struct ieee80211vap *vap; +- int ic_opmode; ++ int ic_opmode = IEEE80211_M_STA; + + if (ic->ic_dev->flags & IFF_RUNNING) { + /* needs to disable hardware too */ +@@ -1271,8 +1269,12 @@ + } else + ic_opmode = opmode; + break; +- case IEEE80211_M_HOSTAP: + case IEEE80211_M_WDS: ++ if (!master) ++ return NULL; ++ ic_opmode = ic->ic_opmode; ++ break; ++ case IEEE80211_M_HOSTAP: + /* 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 @@ + } + + avp = dev->priv; +- ieee80211_vap_setup(ic, dev, name, opmode, flags); ++ ieee80211_vap_setup(ic, dev, name, opmode, flags, master); + /* override with driver methods */ + vap = &avp->av_vap; + avp->av_newstate = vap->iv_newstate; +@@ -4201,8 +4203,7 @@ + if (ic->ic_opmode == IEEE80211_M_STA || + sc->sc_opmode == HAL_M_IBSS || /* NB: AHDEMO too */ + (sc->sc_nostabeacons) || sc->sc_scanning || +- ((ic->ic_opmode == IEEE80211_M_HOSTAP) && +- (ic->ic_protmode != IEEE80211_PROT_NONE))) ++ (ic->ic_opmode == IEEE80211_M_HOSTAP)) + rfilt |= HAL_RX_FILTER_BEACON; + if (sc->sc_nmonvaps > 0) + rfilt |= (HAL_RX_FILTER_CONTROL | HAL_RX_FILTER_BEACON | +@@ -9030,8 +9031,6 @@ + * set sc->beacons if we might need to restart + * them after ath_reset. */ + if (!sc->sc_beacons && +- (TAILQ_FIRST(&ic->ic_vaps)->iv_opmode != +- IEEE80211_M_WDS) && + !txcont_was_active && + !sc->sc_dfs_cac) { + sc->sc_beacons = 1; +--- a/net80211/ieee80211.c ++++ b/net80211/ieee80211.c +@@ -396,7 +396,7 @@ + + int + ieee80211_vap_setup(struct ieee80211com *ic, struct net_device *dev, +- const char *name, int opmode, int flags) ++ const char *name, int opmode, int flags, struct ieee80211vap *master) + { + #define IEEE80211_C_OPMODE \ + (IEEE80211_C_IBSS | IEEE80211_C_HOSTAP | IEEE80211_C_AHDEMO | \ +@@ -510,9 +510,18 @@ + + vap->iv_monitor_crc_errors = 0; + vap->iv_monitor_phy_errors = 0; ++ TAILQ_INIT(&vap->iv_wdslinks); + +- IEEE80211_ADDR_COPY(vap->iv_myaddr, ic->ic_myaddr); +- IEEE80211_ADDR_COPY(vap->iv_bssid, ic->ic_myaddr); ++ if (master && (vap->iv_opmode == IEEE80211_M_WDS)) { ++ vap->iv_master = master; ++ TAILQ_INSERT_TAIL(&master->iv_wdslinks, vap, iv_wdsnext); ++ /* use the same BSSID as the master interface */ ++ IEEE80211_ADDR_COPY(vap->iv_myaddr, vap->iv_master->iv_myaddr); ++ IEEE80211_ADDR_COPY(vap->iv_bssid, vap->iv_master->iv_myaddr); ++ } else { ++ IEEE80211_ADDR_COPY(vap->iv_myaddr, ic->ic_myaddr); ++ IEEE80211_ADDR_COPY(vap->iv_bssid, ic->ic_myaddr); ++ } + /* NB: Defer setting dev_addr so driver can override */ + + ieee80211_crypto_vattach(vap); +@@ -547,7 +556,8 @@ + ifmedia_set(&vap->iv_media, imr.ifm_active); + + IEEE80211_LOCK_IRQ(ic); +- TAILQ_INSERT_TAIL(&ic->ic_vaps, vap, iv_next); ++ if (vap->iv_opmode != IEEE80211_M_WDS) ++ TAILQ_INSERT_TAIL(&ic->ic_vaps, vap, iv_next); + IEEE80211_UNLOCK_IRQ(ic); + + IEEE80211_ADDR_COPY(dev->dev_addr, vap->iv_myaddr); +@@ -579,10 +589,24 @@ + { + struct ieee80211com *ic = vap->iv_ic; + struct net_device *dev = vap->iv_dev; ++ struct ieee80211vap *avp; ++ ++ /* Drop all WDS links that belong to this vap */ ++ while ((avp = TAILQ_FIRST(&vap->iv_wdslinks)) != NULL) { ++ ieee80211_stop(avp->iv_dev); ++ ic->ic_vap_delete(avp); ++ } + + IEEE80211_CANCEL_TQUEUE(&vap->iv_stajoin1tq); + IEEE80211_LOCK_IRQ(ic); +- TAILQ_REMOVE(&ic->ic_vaps, vap, iv_next); ++ if (vap->iv_wdsnode) ++ ieee80211_unref_node(&vap->iv_wdsnode); ++ if ((vap->iv_opmode == IEEE80211_M_WDS) && ++ (vap->iv_master != NULL)) ++ TAILQ_REMOVE(&vap->iv_master->iv_wdslinks, vap, iv_wdsnext); ++ else ++ TAILQ_REMOVE(&ic->ic_vaps, vap, iv_next); ++ + if (TAILQ_EMPTY(&ic->ic_vaps)) /* reset to supported mode */ + ic->ic_opmode = IEEE80211_M_STA; + IEEE80211_UNLOCK_IRQ(ic); +--- a/net80211/ieee80211_ioctl.h ++++ b/net80211/ieee80211_ioctl.h +@@ -474,7 +474,7 @@ + #define IEEE80211_IOC_DTIM_PERIOD 52 /* DTIM period (beacons) */ + #define IEEE80211_IOC_BEACON_INTERVAL 53 /* beacon interval (ms) */ + #define IEEE80211_IOC_ADDMAC 54 /* add sta to MAC ACL table */ +-#define IEEE80211_IOC_DELMAC 55 /* del sta from MAC ACL table */ ++#define IEEE80211_IOC_SETMAC 55 /* set interface wds mac addr */ + #define IEEE80211_IOC_FF 56 /* ATH fast frames (on, off) */ + #define IEEE80211_IOC_TURBOP 57 /* ATH turbo' (on, off) */ + #define IEEE80211_IOC_APPIEBUF 58 /* IE in the management frame */ +@@ -552,8 +552,8 @@ + #define IEEE80211_IOCTL_HALMAP (SIOCIWFIRSTPRIV+21) + #define IEEE80211_IOCTL_ADDMAC (SIOCIWFIRSTPRIV+22) + #define IEEE80211_IOCTL_DELMAC (SIOCIWFIRSTPRIV+24) +-#define IEEE80211_IOCTL_WDSADDMAC (SIOCIWFIRSTPRIV+26) +-#define IEEE80211_IOCTL_WDSDELMAC (SIOCIWFIRSTPRIV+28) ++#define IEEE80211_IOCTL_WDSADDMAC (SIOCIWFIRSTPRIV+25) ++#define IEEE80211_IOCTL_WDSSETMAC (SIOCIWFIRSTPRIV+26) + #define IEEE80211_IOCTL_KICKMAC (SIOCIWFIRSTPRIV+30) + #define IEEE80211_IOCTL_SETSCANLIST (SIOCIWFIRSTPRIV+31) + +--- a/net80211/ieee80211_linux.h ++++ b/net80211/ieee80211_linux.h +@@ -650,5 +650,5 @@ + int ieee80211_ioctl_create_vap(struct ieee80211com *, struct ifreq *, + struct net_device *); + struct ieee80211vap *ieee80211_create_vap(struct ieee80211com *, char *, +- struct net_device *, int, int); ++ struct net_device *, int, int, struct ieee80211vap *); + #endif /* _NET80211_IEEE80211_LINUX_H_ */ +--- a/net80211/ieee80211_var.h ++++ b/net80211/ieee80211_var.h +@@ -187,6 +187,12 @@ + struct ieee80211_proc_entry *iv_proc_entries; + struct vlan_group *iv_vlgrp; /* vlan group state */ + ++ /* list of wds links */ ++ TAILQ_HEAD(, ieee80211vap) iv_wdslinks; ++ TAILQ_ENTRY(ieee80211vap) iv_wdsnext; ++ struct ieee80211vap *iv_master; ++ struct ieee80211_node *iv_wdsnode; ++ + TAILQ_ENTRY(ieee80211vap) iv_next; /* list of vap instances */ + struct ieee80211com *iv_ic; /* back ptr to common state */ + u_int32_t iv_debug; /* debug msg flags */ +@@ -447,7 +453,7 @@ + atomic_t ic_node_counter; + /* Virtual AP create/delete */ + struct ieee80211vap *(*ic_vap_create)(struct ieee80211com *, +- const char *, int, int, struct net_device *); ++ const char *, int, int, struct net_device *, struct ieee80211vap *); + void (*ic_vap_delete)(struct ieee80211vap *); + + /* Send/recv 802.11 management frame */ +@@ -703,7 +709,7 @@ + int ieee80211_ifattach(struct ieee80211com *); + void ieee80211_ifdetach(struct ieee80211com *); + int ieee80211_vap_setup(struct ieee80211com *, struct net_device *, +- const char *, int, int); ++ const char *, int, int, struct ieee80211vap *); + int ieee80211_vap_attach(struct ieee80211vap *, ifm_change_cb_t, ifm_stat_cb_t); + void ieee80211_vap_detach(struct ieee80211vap *); + void ieee80211_mark_dfs(struct ieee80211com *, struct ieee80211_channel *); +--- a/net80211/ieee80211_wireless.c ++++ b/net80211/ieee80211_wireless.c +@@ -2190,7 +2190,7 @@ + ieee80211_scan_flush(ic); /* NB: could optimize */ + + if (!(xrvap = ic->ic_vap_create(ic, name, IEEE80211_M_HOSTAP, +- IEEE80211_VAP_XR | IEEE80211_CLONE_BSSID, dev))) ++ IEEE80211_VAP_XR | IEEE80211_CLONE_BSSID, dev, NULL))) + return; + + /* We use iv_xrvap to link to the parent VAP as well */ +@@ -3801,74 +3801,51 @@ + return 0; + } + ++#define WDSNAME ".wds%d" + static int +-ieee80211_ioctl_wdsmac(struct net_device *dev, struct iw_request_info *info, ++ieee80211_ioctl_wdsaddmac(struct net_device *dev, struct iw_request_info *info, + void *w, char *extra) + { + struct ieee80211vap *vap = dev->priv; + struct sockaddr *sa = (struct sockaddr *)extra; ++ struct ieee80211com *ic = vap->iv_ic; ++ struct ieee80211vap *avp; ++ char *name; + +- if (!IEEE80211_ADDR_NULL(vap->wds_mac)) { +- printk("%s: Failed to add WDS MAC: " MAC_FMT "\n", dev->name, +- MAC_ADDR(sa->sa_data)); +- printk("%s: Device already has WDS mac address attached," +- " remove first\n", dev->name); +- return -1; +- } +- +- memcpy(vap->wds_mac, sa->sa_data, IEEE80211_ADDR_LEN); +- +- printk("%s: Added WDS MAC: " MAC_FMT "\n", dev->name, +- MAC_ADDR(vap->wds_mac)); ++ name = kmalloc(strlen(vap->iv_dev->name) + sizeof(WDSNAME) + 1, GFP_KERNEL); ++ if (!name) ++ return -ENOMEM; + +- if (IS_UP(vap->iv_dev)) { +- /* Force us back to scan state to force us to go back through RUN +- * state and create/pin the WDS peer node into memory. */ +- return ieee80211_new_state(vap, IEEE80211_S_SCAN, 0); +- } ++ strcpy(name, vap->iv_dev->name); ++ strcat(name, WDSNAME); ++ avp = ieee80211_create_vap(ic, name, ic->ic_dev, IEEE80211_M_WDS, 0, vap); ++ kfree(name); ++ if (!avp) ++ return -ENOMEM; + ++ memcpy(avp->wds_mac, sa->sa_data, IEEE80211_ADDR_LEN); + return 0; + } ++#undef WDSNAME + + static int +-ieee80211_ioctl_wdsdelmac(struct net_device *dev, struct iw_request_info *info, ++ieee80211_ioctl_wdssetmac(struct net_device *dev, struct iw_request_info *info, + void *w, char *extra) + { + struct ieee80211vap *vap = dev->priv; + struct sockaddr *sa = (struct sockaddr *)extra; +- struct ieee80211com *ic = vap->iv_ic; +- struct ieee80211_node *wds_ni; + +- /* WDS Mac address filed already? */ +- if (IEEE80211_ADDR_NULL(vap->wds_mac)) +- return 0; ++ if (vap->iv_opmode != IEEE80211_M_WDS) ++ return -EINVAL; + +- /* Compare suplied MAC address with WDS MAC of this interface +- * remove when mac address is known +- */ +- if (memcmp(vap->wds_mac, sa->sa_data, IEEE80211_ADDR_LEN) == 0) { +- if (IS_UP(vap->iv_dev)) { +- wds_ni = ieee80211_find_txnode(vap, vap->wds_mac); +- if (wds_ni != NULL) { +- /* Release reference created by find node */ +- ieee80211_unref_node(&wds_ni); +- /* Release reference created by transition to RUN state, +- * [pinning peer node into the table] */ +- ieee80211_unref_node(&wds_ni); +- } +- } +- memset(vap->wds_mac, 0x00, IEEE80211_ADDR_LEN); +- if (IS_UP(vap->iv_dev)) { +- /* This leaves a dead WDS node, until started again */ +- return ic->ic_reset(ic->ic_dev); +- } +- return 0; ++ memcpy(vap->wds_mac, sa->sa_data, IEEE80211_ADDR_LEN); ++ if (IS_UP(vap->iv_dev)) { ++ /* Force us back to scan state to force us to go back through RUN ++ * state and create/pin the WDS peer node into memory. */ ++ return ieee80211_new_state(vap, IEEE80211_S_SCAN, 0); + } + +- printk("%s: WDS MAC address " MAC_FMT " is not known by this interface\n", +- dev->name, MAC_ADDR(sa->sa_data)); +- +- return -1; ++ return 0; + } + + /* +@@ -5391,8 +5368,8 @@ + IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0, "kickmac"}, + { IEEE80211_IOCTL_WDSADDMAC, + IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,"wds_add" }, +- { IEEE80211_IOCTL_WDSDELMAC, +- IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,"wds_del" }, ++ { IEEE80211_IOCTL_WDSSETMAC, ++ IW_PRIV_TYPE_ADDR | IW_PRIV_SIZE_FIXED | 1, 0,"wds_set" }, + { IEEE80211_IOCTL_SETCHANLIST, + IW_PRIV_TYPE_CHANLIST | IW_PRIV_SIZE_FIXED, 0,"setchanlist" }, + { IEEE80211_IOCTL_GETCHANLIST, +@@ -5884,8 +5861,8 @@ + #endif + set_priv(IEEE80211_IOCTL_ADDMAC, ieee80211_ioctl_addmac), + set_priv(IEEE80211_IOCTL_DELMAC, ieee80211_ioctl_delmac), +- set_priv(IEEE80211_IOCTL_WDSADDMAC, ieee80211_ioctl_wdsmac), +- set_priv(IEEE80211_IOCTL_WDSDELMAC, ieee80211_ioctl_wdsdelmac), ++ set_priv(IEEE80211_IOCTL_WDSADDMAC, ieee80211_ioctl_wdsaddmac), ++ set_priv(IEEE80211_IOCTL_WDSSETMAC, ieee80211_ioctl_wdssetmac), + set_priv(IEEE80211_IOCTL_KICKMAC, ieee80211_ioctl_kickmac), + set_priv(IEEE80211_IOCTL_SETSCANLIST, ieee80211_ioctl_setscanlist), + #ifdef ATH_REVERSE_ENGINEERING +@@ -5956,7 +5933,7 @@ + + strncpy(name, cp.icp_name, sizeof(name)); + +- vap = ieee80211_create_vap(ic, name, mdev, cp.icp_opmode, cp.icp_flags); ++ vap = ieee80211_create_vap(ic, name, mdev, cp.icp_opmode, cp.icp_flags, NULL); + if (vap == NULL) + return -EIO; + +@@ -5973,9 +5950,9 @@ + */ + struct ieee80211vap* + ieee80211_create_vap(struct ieee80211com *ic, char *name, +- struct net_device *mdev, int opmode, int opflags) ++ struct net_device *mdev, int opmode, int opflags, struct ieee80211vap *master) + { +- return ic->ic_vap_create(ic, name, opmode, opflags, mdev); ++ return ic->ic_vap_create(ic, name, opmode, opflags, mdev, master); + } + EXPORT_SYMBOL(ieee80211_create_vap); + +--- a/net80211/ieee80211_input.c ++++ b/net80211/ieee80211_input.c +@@ -201,6 +201,7 @@ + struct ieee80211_node * ni = ni_or_null; + struct ieee80211com *ic = vap->iv_ic; + struct net_device *dev = vap->iv_dev; ++ struct ieee80211_node *ni_wds = NULL; + struct ieee80211_frame *wh; + struct ieee80211_key *key; + struct ether_header *eh; +@@ -545,11 +546,29 @@ + * the node table for the packet source address (addr4). + * If not, add one. + */ +- /* XXX: Useless node mgmt API; make better */ ++ ++ /* check for wds link first */ + if (dir == IEEE80211_FC1_DIR_DSTODS) { +- struct ieee80211_node_table *nt; ++ struct ieee80211vap *avp; ++ ++ 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); ++ ni_wds = avp->iv_wdsnode; ++ IEEE80211_UNLOCK_IRQ(ni->ni_ic); ++ break; ++ } ++ } ++ if (ni_wds != NULL) { ++ ieee80211_unref_node(&ni); ++ ni = ieee80211_ref_node(ni_wds); ++ } ++ } ++ ++ /* XXX: Useless node mgmt API; make better */ ++ if ((dir == IEEE80211_FC1_DIR_DSTODS) && !ni_wds) { ++ struct ieee80211_node_table *nt = &ic->ic_sta; + struct ieee80211_frame_addr4 *wh4; +- struct ieee80211_node *ni_wds; + + if (!(vap->iv_flags_ext & IEEE80211_FEXT_WDS)) { + IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, +@@ -557,7 +576,6 @@ + goto err; + } + wh4 = (struct ieee80211_frame_addr4 *)skb->data; +- nt = &ic->ic_sta; + ni_wds = ieee80211_find_wds_node(nt, wh4->i_addr4); + /* Last call increments ref count if !NULL */ + if ((ni_wds != NULL) && (ni_wds != ni)) { +@@ -3084,8 +3102,7 @@ + (vap->iv_opmode == IEEE80211_M_STA && ni->ni_associd) || + (vap->iv_opmode == IEEE80211_M_IBSS) || + ((subtype == IEEE80211_FC0_SUBTYPE_BEACON) && +- (vap->iv_opmode == IEEE80211_M_HOSTAP) && +- (ic->ic_protmode != IEEE80211_PROT_NONE)))) { ++ (vap->iv_opmode == IEEE80211_M_HOSTAP)))) { + vap->iv_stats.is_rx_mgtdiscard++; + return; + } +@@ -3471,13 +3488,53 @@ + */ + if (ic->ic_flags & IEEE80211_F_SCAN) { + ieee80211_add_scan(vap, &scan, wh, subtype, rssi, rtsf); +- return; + } +- if ((vap->iv_opmode == IEEE80211_M_IBSS) && +- (scan.capinfo & IEEE80211_CAPINFO_IBSS)) { ++ /* NB: Behavior of WDS-Link and Ad-Hoc is very similar here: ++ * When we receive a beacon that belongs to the AP that we're ++ * connected to, use it to refresh the local node info. ++ * If no node is found, go through the vap's wds link table ++ * and try to find the sub-vap that is interested in this address ++ */ ++ if (((vap->iv_opmode == IEEE80211_M_IBSS) && ++ (scan.capinfo & IEEE80211_CAPINFO_IBSS)) || ++ (((vap->iv_opmode == IEEE80211_M_HOSTAP) || ++ (vap->iv_opmode == IEEE80211_M_WDS)) && ++ (scan.capinfo & IEEE80211_CAPINFO_ESS))) { ++ struct ieee80211vap *avp = NULL; ++ ++ 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)) { ++ found = 1; ++ break; ++ } ++ } ++ if (found) { ++ if (!avp->iv_wdsnode) ++ break; ++ ni = ni_or_null = avp->iv_wdsnode; ++ } else { ++ avp = NULL; ++ } ++ } ++ IEEE80211_UNLOCK_IRQ(vap->iv_ic); ++ ++ + if (ni_or_null == NULL) { +- /* Create a new entry in the neighbor table. */ +- ni = ieee80211_add_neighbor(vap, wh, &scan); ++ if (avp) { ++ IEEE80211_LOCK_IRQ(ic); ++ ni = ieee80211_add_neighbor(avp, wh, &scan); ++ /* force assoc */ ++ ni->ni_associd |= 0xc000; ++ avp->iv_wdsnode = ieee80211_ref_node(ni); ++ IEEE80211_UNLOCK_IRQ(ic); ++ } else if (vap->iv_opmode == IEEE80211_M_IBSS) { ++ /* Create a new entry in the neighbor table. */ ++ ni = ieee80211_add_neighbor(vap, wh, &scan); ++ } + } else { + /* + * Copy data from beacon to neighbor table. +@@ -3490,6 +3547,7 @@ + IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3); + memcpy(ni->ni_tstamp.data, scan.tstamp, + sizeof(ni->ni_tstamp)); ++ ni->ni_inact = ni->ni_inact_reload; + ni->ni_intval = + IEEE80211_BINTVAL_SANITISE(scan.bintval); + ni->ni_capinfo = scan.capinfo; +--- a/net80211/ieee80211_node.c ++++ b/net80211/ieee80211_node.c +@@ -1553,22 +1553,24 @@ + ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_PS_POLL) + struct ieee80211_node_table *nt; + struct ieee80211_node *ni; ++ u_int8_t *addr; ++ ++ if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/) ++ addr = wh->i_addr1; ++ else ++ addr = wh->i_addr2; ++ ++ if (IEEE80211_IS_MULTICAST(addr)) ++ return NULL; + + /* XXX check ic_bss first in station mode */ + /* XXX 4-address frames? */ + nt = &ic->ic_sta; + IEEE80211_NODE_TABLE_LOCK_IRQ(nt); +- if (IS_CTL(wh) && !IS_PSPOLL(wh) /*&& !IS_RTS(ah)*/) + #ifdef IEEE80211_DEBUG_REFCNT +- ni = ieee80211_find_node_locked_debug(nt, wh->i_addr1, func, line); ++ ni = ieee80211_find_node_locked_debug(nt, addr, func, line); + #else +- ni = ieee80211_find_node_locked(nt, wh->i_addr1); +-#endif +- else +-#ifdef IEEE80211_DEBUG_REFCNT +- ni = ieee80211_find_node_locked_debug(nt, wh->i_addr2, func, line); +-#else +- ni = ieee80211_find_node_locked(nt, wh->i_addr2); ++ ni = ieee80211_find_node_locked(nt, addr); + #endif + IEEE80211_NODE_TABLE_UNLOCK_IRQ(nt); + +@@ -1669,6 +1671,11 @@ + { + struct ieee80211vap *vap = ni->ni_vap; + ++ IEEE80211_LOCK_IRQ(ni->ni_ic); ++ if (vap && ni == vap->iv_wdsnode) ++ vap->iv_wdsnode = NULL; ++ IEEE80211_UNLOCK_IRQ(ni->ni_ic); ++ + atomic_dec(&ni->ni_ic->ic_node_counter); + node_print_message(IEEE80211_MSG_NODE|IEEE80211_MSG_NODE_REF, + 1 /* show counter */, +@@ -1781,22 +1788,6 @@ + jiffies > ni->ni_rxfragstamp + HZ) { + ieee80211_dev_kfree_skb(&ni->ni_rxfrag); + } +- /* +- * Special case ourself; we may be idle for extended periods +- * of time and regardless reclaiming our state is wrong. +- * Special case a WDS link: it may be dead or idle, but it is +- * never ok to reclaim it, as this will block transmissions +- * and nobody will recreate the node when the WDS peer is +- * available again. */ +- if ((ni == ni->ni_vap->iv_bss) || +- (ni->ni_vap->iv_opmode == IEEE80211_M_WDS && +- !memcmp(ni->ni_macaddr, ni->ni_vap->wds_mac, ETH_ALEN))) +- { +- /* NB: don't permit it to go negative */ +- if (ni->ni_inact > 0) +- ni->ni_inact--; +- continue; +- } + ni->ni_inact--; + if (ni->ni_associd != 0 || isadhoc) { + struct ieee80211vap *vap = ni->ni_vap; +--- a/net80211/ieee80211_output.c ++++ b/net80211/ieee80211_output.c +@@ -246,10 +246,16 @@ + * things like power save. + */ + eh = (struct ether_header *)skb->data; +- if (vap->iv_opmode == IEEE80211_M_WDS) +- ni = ieee80211_find_txnode(vap, vap->wds_mac); +- else ++ if (vap->iv_opmode == IEEE80211_M_WDS) { ++ IEEE80211_LOCK_IRQ(ic); ++ ni = vap->iv_wdsnode; ++ IEEE80211_UNLOCK_IRQ(ic); ++ if (!ni) ++ goto bad; ++ ni = ieee80211_ref_node(vap->iv_wdsnode); ++ } else { + ni = ieee80211_find_txnode(vap, eh->ether_dhost); ++ } + if (ni == NULL) { + /* NB: ieee80211_find_txnode does stat+msg */ + goto bad; +@@ -788,7 +794,7 @@ + break; + case IEEE80211_M_WDS: + use4addr = 1; +- ismulticast = IEEE80211_IS_MULTICAST(ni->ni_macaddr); ++ ismulticast = 0; + break; + case IEEE80211_M_HOSTAP: + if (!IEEE80211_IS_MULTICAST(eh.ether_dhost) && +@@ -973,7 +979,7 @@ + break; + case IEEE80211_M_WDS: + wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; +- IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); ++ IEEE80211_ADDR_COPY(wh->i_addr1, vap->wds_mac); + IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); + IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); + IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost); +--- a/tools/athkey.c ++++ b/tools/athkey.c +@@ -118,7 +118,7 @@ + IOCTL_ERR(IEEE80211_IOCTL_ADDMAC), + IOCTL_ERR(IEEE80211_IOCTL_DELMAC), + IOCTL_ERR(IEEE80211_IOCTL_WDSADDMAC), +- IOCTL_ERR(IEEE80211_IOCTL_WDSDELMAC), ++ IOCTL_ERR(IEEE80211_IOCTL_WDSSETMAC), + IOCTL_ERR(IEEE80211_IOCTL_READREG), + IOCTL_ERR(IEEE80211_IOCTL_WRITEREG), + }; +--- a/tools/athchans.c ++++ b/tools/athchans.c +@@ -118,7 +118,7 @@ + IOCTL_ERR(IEEE80211_IOCTL_ADDMAC), + IOCTL_ERR(IEEE80211_IOCTL_DELMAC), + IOCTL_ERR(IEEE80211_IOCTL_WDSADDMAC), +- IOCTL_ERR(IEEE80211_IOCTL_WDSDELMAC), ++ IOCTL_ERR(IEEE80211_IOCTL_WDSSETMAC), + IOCTL_ERR(IEEE80211_IOCTL_READREG), + IOCTL_ERR(IEEE80211_IOCTL_WRITEREG), + }; +--- a/tools/wlanconfig.c ++++ b/tools/wlanconfig.c +@@ -968,7 +968,7 @@ + IOCTL_ERR(IEEE80211_IOCTL_ADDMAC), + IOCTL_ERR(IEEE80211_IOCTL_DELMAC), + IOCTL_ERR(IEEE80211_IOCTL_WDSADDMAC), +- IOCTL_ERR(IEEE80211_IOCTL_WDSDELMAC), ++ IOCTL_ERR(IEEE80211_IOCTL_WDSSETMAC), + IOCTL_ERR(IEEE80211_IOCTL_READREG), + IOCTL_ERR(IEEE80211_IOCTL_WRITEREG), + }; +--- a/net80211/ieee80211_proto.c ++++ b/net80211/ieee80211_proto.c +@@ -1557,57 +1557,12 @@ + switch (ostate) { + case IEEE80211_S_INIT: + if (vap->iv_opmode == IEEE80211_M_MONITOR || +- vap->iv_opmode == IEEE80211_M_WDS || + vap->iv_opmode == IEEE80211_M_HOSTAP) { + /* + * Already have a channel; bypass the + * scan and startup immediately. + */ + ieee80211_create_ibss(vap, ic->ic_curchan); +- +- /* In WDS mode, allocate and initialize peer node. */ +- if (vap->iv_opmode == IEEE80211_M_WDS) { +- /* XXX: This is horribly non-atomic. */ +- struct ieee80211_node *wds_ni = +- ieee80211_find_node(&ic->ic_sta, +- vap->wds_mac); +- +- if (wds_ni == NULL) { +- wds_ni = ieee80211_alloc_node_table( +- vap, +- vap->wds_mac); +- if (wds_ni != NULL) { +- ieee80211_add_wds_addr( +- &ic->ic_sta, +- wds_ni, +- vap->wds_mac, +- 1); +- ieee80211_ref_node(wds_ni); /* pin in memory */ +- } +- else +- IEEE80211_DPRINTF( +- vap, +- IEEE80211_MSG_NODE, +- "%s: Unable to " +- "allocate node for " +- "WDS: " MAC_FMT "\n", +- __func__, +- MAC_ADDR( +- vap->wds_mac) +- ); +- } +- +- if (wds_ni != NULL) { +- ieee80211_node_authorize(wds_ni); +- wds_ni->ni_chan = +- vap->iv_bss->ni_chan; +- wds_ni->ni_capinfo = +- ni->ni_capinfo; +- wds_ni->ni_associd = 1; +- wds_ni->ni_ath_flags = +- vap->iv_ath_cap; +- } +- } + break; + } + /* fall thru... */ -- cgit v1.2.3