From fdb032fd772da4d6a5a77a166e5f90c631114133 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@openwrt.org>
Date: Sat, 17 Oct 2009 04:56:05 +0000
Subject: [PATCH] madwifi: fix various noderef/memleak issues

SVN-Revision: 18052
---
 .../patches/421-channel_handling.patch        |  19 +-
 .../madwifi/patches/430-use_netdev_priv.patch |  14 +-
 package/madwifi/patches/432-netdev_ops.patch  |   6 +-
 .../madwifi/patches/446-single_module.patch   |   2 +-
 .../madwifi/patches/451-ibss_race_fix.patch   | 332 ++++++++++++++++--
 5 files changed, 325 insertions(+), 48 deletions(-)

diff --git a/package/madwifi/patches/421-channel_handling.patch b/package/madwifi/patches/421-channel_handling.patch
index e5302c1389d7..8424321d76c7 100644
--- a/package/madwifi/patches/421-channel_handling.patch
+++ b/package/madwifi/patches/421-channel_handling.patch
@@ -853,7 +853,7 @@
  	}
  	/* Initialize candidate channels to all available */
  	memcpy(ic->ic_chan_active, ic->ic_chan_avail,
-@@ -311,11 +296,58 @@ ieee80211_ifattach(struct ieee80211com *
+@@ -311,11 +296,59 @@ ieee80211_ifattach(struct ieee80211com *
  	 * When 11g is supported, force the rate set to
  	 * include basic rates suitable for a mixed b/g bss.
  	 */
@@ -866,6 +866,7 @@
 +	if (init)
 +		return;
 +
++	ifmedia_removeall(&ic->ic_media);
 +	ieee80211_media_setup(ic, &ic->ic_media, ic->ic_caps, NULL, NULL);
 +	ieee80211com_media_status(ic->ic_dev, &imr);
 +	ifmedia_set(&ic->ic_media, imr.ifm_active);
@@ -913,7 +914,7 @@
  	/* Setup initial channel settings */
  	ic->ic_bsschan = IEEE80211_CHAN_ANYC;
  	/* Arbitrarily pick the first channel */
-@@ -327,6 +359,7 @@ ieee80211_ifattach(struct ieee80211com *
+@@ -327,6 +360,7 @@ ieee80211_ifattach(struct ieee80211com *
  	/* Enable WME by default, if we're capable. */
  	if (ic->ic_caps & IEEE80211_C_WME)
  		ic->ic_flags |= IEEE80211_F_WME;
@@ -921,7 +922,7 @@
  	(void) ieee80211_setmode(ic, ic->ic_curmode);
  
  	/* Store default beacon interval, as nec. */
-@@ -763,7 +796,8 @@ ieee80211_media_setup(struct ieee80211co
+@@ -763,7 +797,8 @@ ieee80211_media_setup(struct ieee80211co
  	struct ieee80211_rateset allrates;
  
  	/* Fill in media characteristics. */
@@ -931,7 +932,7 @@
  	maxrate = 0;
  	memset(&allrates, 0, sizeof(allrates));
  
-@@ -793,7 +827,7 @@ ieee80211_media_setup(struct ieee80211co
+@@ -793,7 +828,7 @@ ieee80211_media_setup(struct ieee80211co
  			ADD(media, IFM_AUTO, mopt | IFM_IEEE80211_WDS);
  		if (mode == IEEE80211_MODE_AUTO)
  			continue;
@@ -940,7 +941,7 @@
  
  		for (i = 0; i < rs->rs_nrates; i++) {
  			rate = rs->rs_rates[i];
-@@ -1207,7 +1241,7 @@ ieee80211_announce(struct ieee80211com *
+@@ -1207,7 +1242,7 @@ ieee80211_announce(struct ieee80211com *
  		if ((ic->ic_modecaps & (1 << mode)) == 0)
  			continue;
  		if_printf(dev, "%s rates: ", ieee80211_phymode_name[mode]);
@@ -949,7 +950,7 @@
  		for (i = 0; i < rs->rs_nrates; i++) {
  			rate = rs->rs_rates[i];
  			mword = ieee80211_rate2media(ic, rate, mode);
-@@ -1417,7 +1451,7 @@ ieee80211com_media_change(struct net_dev
+@@ -1417,7 +1452,7 @@ ieee80211com_media_change(struct net_dev
  			 * now so drivers have a consistent state.
  			 */
  			KASSERT(vap->iv_bss != NULL, ("no bss node"));
@@ -958,7 +959,7 @@
  		}
  		error = -ENETRESET;
  	}
-@@ -1435,7 +1469,7 @@ findrate(struct ieee80211com *ic, enum i
+@@ -1435,7 +1470,7 @@ findrate(struct ieee80211com *ic, enum i
  {
  #define	IEEERATE(_ic,_m,_i) \
  	((_ic)->ic_sup_rates[_m].rs_rates[_i] & IEEE80211_RATE_VAL)
@@ -967,7 +968,7 @@
  	for (i = 0; i < nrates; i++)
  		if (IEEERATE(ic, mode, i) == rate)
  			return i;
-@@ -1877,11 +1911,6 @@ ieee80211_build_countryie(struct ieee802
+@@ -1877,11 +1912,6 @@ ieee80211_build_countryie(struct ieee802
  			if (ieee80211_chan2mode(c) != curmode_noturbo)
  				continue;
  
@@ -979,7 +980,7 @@
  			if (*cur_runlen == 0) {
  				(*cur_runlen)++;
  				*cur_pow = c->ic_maxregpower;
-@@ -1915,7 +1944,7 @@ void
+@@ -1915,7 +1945,7 @@ void
  ieee80211_build_sc_ie(struct ieee80211com *ic)
  {
  	struct ieee80211_ie_sc *ie = &ic->ic_sc_ie;
diff --git a/package/madwifi/patches/430-use_netdev_priv.patch b/package/madwifi/patches/430-use_netdev_priv.patch
index ad2b6d494d0c..642a9d21d231 100644
--- a/package/madwifi/patches/430-use_netdev_priv.patch
+++ b/package/madwifi/patches/430-use_netdev_priv.patch
@@ -1002,7 +1002,7 @@
  #define skb_tail_pointer(_skb) ((_skb)->tail)
 --- a/net80211/ieee80211.c
 +++ b/net80211/ieee80211.c
-@@ -457,7 +457,7 @@ ieee80211_vap_setup(struct ieee80211com 
+@@ -458,7 +458,7 @@ ieee80211_vap_setup(struct ieee80211com 
  #define	IEEE80211_C_OPMODE \
  	(IEEE80211_C_IBSS | IEEE80211_C_HOSTAP | IEEE80211_C_AHDEMO | \
  	 IEEE80211_C_MONITOR)
@@ -1011,7 +1011,7 @@
  	struct net_device *parent = ic->ic_dev;
  	int err;
  
-@@ -1354,7 +1354,7 @@ media_status(enum ieee80211_opmode opmod
+@@ -1355,7 +1355,7 @@ media_status(enum ieee80211_opmode opmod
  static void
  ieee80211com_media_status(struct net_device *dev, struct ifmediareq *imr)
  {
@@ -1020,7 +1020,7 @@
  
  	imr->ifm_status = IFM_AVALID;
  	if (!TAILQ_EMPTY(&ic->ic_vaps))
-@@ -1406,7 +1406,7 @@ media2mode(const struct ifmedia_entry *i
+@@ -1407,7 +1407,7 @@ media2mode(const struct ifmedia_entry *i
  static int
  ieee80211com_media_change(struct net_device *dev)
  {
@@ -1029,7 +1029,7 @@
  	struct ieee80211vap *vap;
  	struct ifmedia_entry *ime = ic->ic_media.ifm_cur;
  	enum ieee80211_phymode newphymode;
-@@ -1510,7 +1510,7 @@ checkrate(struct ieee80211com *ic, enum 
+@@ -1511,7 +1511,7 @@ checkrate(struct ieee80211com *ic, enum 
  int
  ieee80211_media_change(struct net_device *dev)
  {
@@ -1038,7 +1038,7 @@
  	struct ieee80211com *ic = vap->iv_ic;
  	struct ifmedia_entry *ime = vap->iv_media.ifm_cur;
  	enum ieee80211_phymode newmode;
-@@ -1544,7 +1544,7 @@ EXPORT_SYMBOL(ieee80211_media_change);
+@@ -1545,7 +1545,7 @@ EXPORT_SYMBOL(ieee80211_media_change);
  void
  ieee80211_media_status(struct net_device *dev, struct ifmediareq *imr)
  {
@@ -1047,7 +1047,7 @@
  	struct ieee80211com *ic = vap->iv_ic;
  	enum ieee80211_phymode mode;
  	struct ieee80211_rateset *rs;
-@@ -1750,7 +1750,7 @@ EXPORT_SYMBOL(ieee80211_media2rate);
+@@ -1751,7 +1751,7 @@ EXPORT_SYMBOL(ieee80211_media2rate);
  static struct net_device_stats *
  ieee80211_getstats(struct net_device *dev)
  {
@@ -1056,7 +1056,7 @@
  	struct net_device_stats *stats = &vap->iv_devstats;
  
  	/* XXX: Total guess as to what to count where */
-@@ -1789,7 +1789,7 @@ ieee80211_change_mtu(struct net_device *
+@@ -1790,7 +1790,7 @@ ieee80211_change_mtu(struct net_device *
  static void
  ieee80211_set_multicast_list(struct net_device *dev)
  {
diff --git a/package/madwifi/patches/432-netdev_ops.patch b/package/madwifi/patches/432-netdev_ops.patch
index 372000fc8e4c..2e542bfecef8 100644
--- a/package/madwifi/patches/432-netdev_ops.patch
+++ b/package/madwifi/patches/432-netdev_ops.patch
@@ -69,7 +69,7 @@ http://madwifi-project.org/changeset/4005
  	case NETDEV_CHANGENAME:
 --- a/net80211/ieee80211.c
 +++ b/net80211/ieee80211.c
-@@ -450,6 +450,18 @@ ieee80211_ifdetach(struct ieee80211com *
+@@ -451,6 +451,18 @@ ieee80211_ifdetach(struct ieee80211com *
  }
  EXPORT_SYMBOL(ieee80211_ifdetach);
  
@@ -88,7 +88,7 @@ http://madwifi-project.org/changeset/4005
  int
  ieee80211_vap_setup(struct ieee80211com *ic, struct net_device *dev,
  	const char *name, int opmode, int flags, struct ieee80211vap *master)
-@@ -470,16 +482,21 @@ ieee80211_vap_setup(struct ieee80211com 
+@@ -471,16 +483,21 @@ ieee80211_vap_setup(struct ieee80211com 
  		} else
  			strncpy(dev->name, name, sizeof(dev->name));
  	}
@@ -110,7 +110,7 @@ http://madwifi-project.org/changeset/4005
  	dev->tx_queue_len = 0;			/* NB: bypass queuing */
  	dev->hard_header_len = parent->hard_header_len;
  	/*
-@@ -1823,7 +1840,11 @@ ieee80211_set_multicast_list(struct net_
+@@ -1824,7 +1841,11 @@ ieee80211_set_multicast_list(struct net_
  	IEEE80211_UNLOCK_IRQ(ic);
  
  	/* XXX: Merge multicast list into parent device */
diff --git a/package/madwifi/patches/446-single_module.patch b/package/madwifi/patches/446-single_module.patch
index ed02ae8f5eb8..e546b054a810 100644
--- a/package/madwifi/patches/446-single_module.patch
+++ b/package/madwifi/patches/446-single_module.patch
@@ -351,7 +351,7 @@
  #include <linux/module.h>
  #include <linux/skbuff.h>
  #include <linux/netdevice.h>
-@@ -2014,3 +2015,65 @@ ieee80211_build_sc_ie(struct ieee80211co
+@@ -2015,3 +2016,65 @@ ieee80211_build_sc_ie(struct ieee80211co
  int ath_debug_global = 0;
  EXPORT_SYMBOL(ath_debug_global);
  
diff --git a/package/madwifi/patches/451-ibss_race_fix.patch b/package/madwifi/patches/451-ibss_race_fix.patch
index 7785dc1d7874..9be3311fdada 100644
--- a/package/madwifi/patches/451-ibss_race_fix.patch
+++ b/package/madwifi/patches/451-ibss_race_fix.patch
@@ -1,41 +1,184 @@
 --- a/net80211/ieee80211_input.c
 +++ b/net80211/ieee80211_input.c
-@@ -322,7 +322,6 @@ ieee80211_input(struct ieee80211vap * va
+@@ -294,10 +294,10 @@ ieee80211_input(struct ieee80211vap * va
+ 			break;
+ 		case IEEE80211_M_IBSS:
+ 		case IEEE80211_M_AHDEMO:
+-			if (!IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bssid) ||
++			if ((!IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bssid) ||
+ 			    (!IEEE80211_ADDR_EQ(wh->i_addr1, vap->iv_myaddr) &&
+-			     !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+-			     (subtype != IEEE80211_FC0_SUBTYPE_BEACON))) {
++			     !IEEE80211_IS_MULTICAST(wh->i_addr1))) &&
++			     (type == IEEE80211_FC0_TYPE_DATA)) {
+ 				if (!(vap->iv_dev->flags & IFF_PROMISC)) {
+ 					IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT,
+ 						bssid, NULL, "%s", "not to bss");
+@@ -322,22 +322,15 @@ ieee80211_input(struct ieee80211vap * va
  			}
  			/* Do not try to find a node reference if the packet really did come from the BSS */
  			if (type == IEEE80211_FC0_TYPE_DATA && ni == vap->iv_bss &&
 -					!IEEE80211_ADDR_EQ(vap->iv_bss->ni_macaddr, wh->i_addr2) &&
  					IEEE80211_ADDR_EQ(vap->iv_bssid, wh->i_addr3)) {
  				/* Try to find sender in local node table. */
- 				ni = ieee80211_find_node(&ic->ic_sta, wh->i_addr2);
-@@ -3572,10 +3571,12 @@ ieee80211_recv_mgmt(struct ieee80211vap 
+-				ni = ieee80211_find_node(&ic->ic_sta, wh->i_addr2);
++				if (!ni_or_null) {
++					ieee80211_unref_node(&ni);
++					ni = ieee80211_find_txnode(vap, wh->i_addr2);
++				}
+ 				if (ni == NULL) {
+-					/*
+-					 * Fake up a node for this newly discovered
+-					 * member of the IBSS.  This should probably
+-					 * done after an ACL check.
+-					 */
+-					ni = ieee80211_fakeup_adhoc_node(vap,
+-							wh->i_addr2);
+-					if (ni == NULL) {
+-						/* NB: stat kept for alloc failure */
+-						goto err;
+-					}
++					/* NB: stat kept for alloc failure */
++					goto discard;
+ 				}
+ 			}
+ 			iwspy_event(vap, ni, rssi);
+@@ -3553,8 +3546,8 @@ ieee80211_recv_mgmt(struct ieee80211vap 
+ 				(((vap->iv_opmode == IEEE80211_M_HOSTAP) ||
+ 				 (vap->iv_opmode == IEEE80211_M_WDS)) &&
+ 				(scan.capinfo & IEEE80211_CAPINFO_ESS))) {
++			struct ieee80211_node *tni = NULL;
+ 			struct ieee80211vap *avp = NULL;
+-			int do_unref = 0;
+ 			int found = 0;
+ 
+ 			IEEE80211_LOCK_IRQ(vap->iv_ic);
+@@ -3568,14 +3561,12 @@ ieee80211_recv_mgmt(struct ieee80211vap 
+ 					}
+ 				}
+ 				if (found)
+-					ni = ni_or_null = avp->iv_wdsnode;
++					tni = ieee80211_ref_node(avp->iv_wdsnode);
  			} else if (vap->iv_opmode == IEEE80211_M_WDS) {
  				found = 1;
- 				ni = ni_or_null = vap->iv_wdsnode;
+-				ni = ni_or_null = vap->iv_wdsnode;
 -			} else if (vap->iv_opmode == IEEE80211_M_IBSS) {
-+			} else if ((vap->iv_opmode == IEEE80211_M_IBSS) && (vap->iv_state == IEEE80211_S_RUN)) {
- 				ni_or_null = ieee80211_find_node(&ic->ic_sta, wh->i_addr2);
+-				ni_or_null = ieee80211_find_node(&ic->ic_sta, wh->i_addr2);
 -				if (ni_or_null)
-+				if (ni_or_null) {
- 					ni = ni_or_null;
-+					do_unref = 1;
-+				}
+-					ni = ni_or_null;
++				tni = ieee80211_ref_node(vap->iv_wdsnode);
++			} else if ((vap->iv_opmode == IEEE80211_M_IBSS) && (vap->iv_state == IEEE80211_S_RUN)) {
++				tni = ieee80211_find_node(&ic->ic_sta, wh->i_addr2);
  				found = 1;
  			}
  			IEEE80211_UNLOCK_IRQ(vap->iv_ic);
+@@ -3583,20 +3574,21 @@ ieee80211_recv_mgmt(struct ieee80211vap 
+ 			if (!found)
+ 				break;
+ 
+-			if (ni_or_null == NULL) {
++			memcpy(&SKB_CB(skb)->beacon_tsf, scan.tstamp, sizeof(u_int64_t));
++
++			if (tni == NULL) {
+ 				if (avp) {
+ 					IEEE80211_LOCK_IRQ(ic);
+-					ni = ieee80211_add_neighbor(avp, wh, &scan);
++					tni = ieee80211_add_neighbor(avp, wh, &scan);
+ 					/* force assoc */
+-					ni->ni_associd |= 0xc000;
+-					avp->iv_wdsnode = ieee80211_ref_node(ni);
++					tni->ni_associd |= 0xc000;
++					avp->iv_wdsnode = ieee80211_ref_node(tni);
+ 					IEEE80211_UNLOCK_IRQ(ic);
+ 				} else if ((vap->iv_opmode == IEEE80211_M_IBSS) &&
+ 				           IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bssid)) {
+ 					/* Create a new entry in the neighbor table. */
+-					ni = ieee80211_add_neighbor(vap, wh, &scan);
++					tni = ieee80211_add_neighbor(vap, wh, &scan);
+ 				}
+-				do_unref = 1;
+ 			} else {
+ 				/*
+ 				 * Copy data from beacon to neighbor table.
+@@ -3604,39 +3596,38 @@ ieee80211_recv_mgmt(struct ieee80211vap 
+ 				 * ieee80211_add_neighbor(), so we just copy
+ 				 * everything over to be safe.
+ 				 */
+-				ni->ni_esslen = scan.ssid[1];
+-				memcpy(ni->ni_essid, scan.ssid + 2, scan.ssid[1]);
+-				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 = 
++				tni->ni_esslen = scan.ssid[1];
++				memcpy(tni->ni_essid, scan.ssid + 2, scan.ssid[1]);
++				IEEE80211_ADDR_COPY(tni->ni_bssid, wh->i_addr3);
++				memcpy(tni->ni_tstamp.data, scan.tstamp,
++					sizeof(tni->ni_tstamp));
++				tni->ni_inact = tni->ni_inact_reload;
++				tni->ni_intval =
+ 					IEEE80211_BINTVAL_SANITISE(scan.bintval);
+-				ni->ni_capinfo = scan.capinfo;
+-				ni->ni_chan = ic->ic_curchan;
+-				ni->ni_fhdwell = scan.fhdwell;
+-				ni->ni_fhindex = scan.fhindex;
+-				ni->ni_erp = scan.erp;
+-				ni->ni_timoff = scan.timoff;
++				tni->ni_capinfo = scan.capinfo;
++				tni->ni_chan = ic->ic_curchan;
++				tni->ni_fhdwell = scan.fhdwell;
++				tni->ni_fhindex = scan.fhindex;
++				tni->ni_erp = scan.erp;
++				tni->ni_timoff = scan.timoff;
+ 				if (scan.wme != NULL)
+-					ieee80211_saveie(&ni->ni_wme_ie, scan.wme);
++					ieee80211_saveie(&tni->ni_wme_ie, scan.wme);
+ 				if (scan.wpa != NULL)
+-					ieee80211_saveie(&ni->ni_wpa_ie, scan.wpa);
++					ieee80211_saveie(&tni->ni_wpa_ie, scan.wpa);
+ 				if (scan.rsn != NULL)
+-					ieee80211_saveie(&ni->ni_rsn_ie, scan.rsn);
++					ieee80211_saveie(&tni->ni_rsn_ie, scan.rsn);
+ 				if (scan.ath != NULL)
+-					ieee80211_saveath(ni, scan.ath);
++					ieee80211_saveath(tni, scan.ath);
+ 
+ 				/* NB: must be after ni_chan is setup */
+-				ieee80211_setup_rates(ni, scan.rates,
++				ieee80211_setup_rates(tni, scan.rates,
+ 					scan.xrates, IEEE80211_F_DOSORT);
+ 			}
+-			if (ni != NULL) {
+-				ni->ni_rssi = rssi;
+-				ni->ni_rtsf = rtsf;
+-				ni->ni_last_rx = jiffies;
+-				if (do_unref)
+-					ieee80211_unref_node(&ni);
++			if (tni != NULL) {
++				tni->ni_rssi = rssi;
++				tni->ni_rtsf = rtsf;
++				tni->ni_last_rx = jiffies;
++				ieee80211_unref_node(&tni);
+ 			}
+ 		}
+ 		break;
 --- a/net80211/ieee80211_node.c
 +++ b/net80211/ieee80211_node.c
-@@ -317,16 +317,16 @@ ieee80211_create_ibss(struct ieee80211va
+@@ -53,6 +53,7 @@
+ 
+ #include <net80211/ieee80211_var.h>
+ #include <net80211/if_athproto.h>
++#include <net80211/ieee80211_node.h>
+ 
+ /*
+  * Association IDs are managed with a bit vector.
+@@ -317,16 +318,11 @@ 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_txnode(vap, vap->iv_myaddr);
-+	ni = ieee80211_find_node(&ic->ic_sta, vap->iv_myaddr);
-+	if (ni) {
-+		ieee80211_node_leave(ni);
-+		ieee80211_unref_node(&ni);
-+	}
-+
++	ieee80211_node_table_reset(&ic->ic_sta, vap);
 +	ni = ieee80211_alloc_node_table(vap, vap->iv_myaddr);
  	if (ni == NULL) {
 -		ni = ieee80211_alloc_node_table(vap, vap->iv_myaddr);
@@ -51,23 +194,50 @@
  	}
  
  	IEEE80211_ADDR_COPY(ni->ni_bssid, vap->iv_myaddr);
-@@ -759,6 +759,9 @@ ieee80211_sta_join(struct ieee80211vap *
- 	ieee80211_setup_rates(ni, se->se_rates, se->se_xrates,
- 		IEEE80211_F_DOSORT | IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
+@@ -429,8 +425,8 @@ ieee80211_reset_bss(struct ieee80211vap 
+ 			  __func__, ni, MAC_ADDR(vap->iv_myaddr));
+ 	KASSERT(ni != NULL, ("unable to setup inital BSS node"));
  
-+	if (vap->iv_opmode == IEEE80211_M_IBSS)
-+		ieee80211_node_table_reset(&vap->iv_ic->ic_sta, vap);
-+
- 	return ieee80211_sta_join1(PASS_NODE(ni));
- }
- EXPORT_SYMBOL(ieee80211_sta_join);
+-	vap->iv_bss = ieee80211_ref_node(ni);
+-	KASSERT((atomic_read(&vap->iv_bss->ni_refcnt) == 3), 
++	vap->iv_bss = ni;
++	KASSERT((atomic_read(&vap->iv_bss->ni_refcnt) == 2),
+ 		("wrong refcount for new node."));
+ 
+ 	if (obss != NULL) {
+@@ -647,7 +643,7 @@ ieee80211_sta_join1(struct ieee80211_nod
+ 		(vap->iv_state == IEEE80211_S_RUN) && bssid_equal(obss, selbs)); */
+ 	vap->iv_bss = selbs;
+ 	IEEE80211_ADDR_COPY(vap->iv_bssid, selbs->ni_bssid);
+-	if (obss != NULL) {
++	if ((obss != NULL) && (obss != selbs)) {
+ 		if (obss->ni_table)
+ 			ieee80211_node_leave(obss);
+ 		ieee80211_unref_node(&obss);
 --- a/ath/if_ath.c
 +++ b/ath/if_ath.c
-@@ -6655,10 +6655,8 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+@@ -6625,14 +6625,6 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+ 
+ 	sc->sc_recv_mgmt(vap, ni_or_null, skb, subtype, rssi, rtsf);
+ 
+-	/* Lookup the new node if any (this grabs a reference to it) */
+-	ni = ieee80211_find_rxnode(vap->iv_ic, vap,
+-	         (const struct ieee80211_frame_min *)skb->data);
+-	if (ni == NULL) {
+-		DPRINTF(sc, ATH_DEBUG_BEACON, "Dropping; node unknown.\n");
+-		return;
+-	}
+-
+ 	switch (subtype) {
+ 	case IEEE80211_FC0_SUBTYPE_BEACON:
+ 		/* update RSSI statistics for use by the HAL */
+@@ -6654,11 +6646,9 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+ 			 * we do the IBSS merging in software. Also do not merge
  			 * if the difference it too small. Otherwise we are playing
  			 * tsf-pingpong with other vendors drivers */
- 			beacon_tsf = le64_to_cpu(ni->ni_tstamp.tsf);
+-			beacon_tsf = le64_to_cpu(ni->ni_tstamp.tsf);
 -			if (beacon_tsf > rtsf + 0xffff) {
++			beacon_tsf = le64_to_cpu(SKB_CB(skb)->beacon_tsf);
 +			if (beacon_tsf > rtsf + 0xffff)
  				ath_hal_settsf64(sc->sc_ah, beacon_tsf - rtsf);
 -				ieee80211_ibss_merge(ni);
@@ -75,3 +245,109 @@
  			break;
  		}
  		/* NB: Fall Through */
+@@ -6680,13 +6670,21 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+ 			hw_tsf = ath_hal_gettsf64(sc->sc_ah);
+ 			hw_tu  = hw_tsf >> 10;
+ 
+-			beacon_tsf = le64_to_cpu(ni->ni_tstamp.tsf);
++			beacon_tsf = le64_to_cpu(SKB_CB(skb)->beacon_tsf);
+ 			beacon_tu  = beacon_tsf >> 10;
+ 
++			if (!beacon_tsf)
++				break;
++
++			if (IEEE80211_ADDR_EQ(wh->i_addr3, vap->iv_bssid))
++				break;
++
+ 			DPRINTF(sc, ATH_DEBUG_BEACON,
+-					"Beacon transmitted at %10llx, "
++					"Beacon transmitted from "MAC_FMT" ("MAC_FMT") at %10llx, "
+ 					"received at %10llx(%lld), hw TSF "
+ 					"%10llx(%lld)\n",
++					MAC_ADDR(wh->i_addr3),
++					MAC_ADDR(vap->iv_bssid),
+ 					beacon_tsf,
+ 					rtsf, rtsf - beacon_tsf,
+ 					hw_tsf, hw_tsf - beacon_tsf);
+@@ -6699,39 +6697,13 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+ 				do_merge = 1;
+ 			}
+ 
+-			/* Check sc_nexttbtt */
+-			if (sc->sc_nexttbtt < hw_tu) {
+-				DPRINTF(sc, ATH_DEBUG_BEACON,
+-					"sc_nexttbtt (%8x TU) is in the past "
+-					"(tsf %8x TU), updating timers\n",
+-					sc->sc_nexttbtt, hw_tu);
+-				do_merge = 1;
+-			}
+-
+-			intval = ni->ni_intval & HAL_BEACON_PERIOD;
+-#if 0
+-			/* This code is disabled since it would produce
+-			 * unwanted merge. For instance, in a two nodes network
+-			 * A & B, A can merge to B and at the same time, B will
+-			 * merge to A, still having a split */
+-			if (intval != 0) {
+-				if ((sc->sc_nexttbtt % intval) !=
+-						(beacon_tu % intval)) {
+-					DPRINTF(sc, ATH_DEBUG_BEACON,
+-							"ibss merge: "
+-							"sc_nexttbtt %10x TU "
+-							"(%3d) beacon %10x TU "
+-							"(%3d)\n",
+-							sc->sc_nexttbtt,
+-							sc->sc_nexttbtt % intval,
+-							beacon_tu,
+-							beacon_tu % intval);
+-					do_merge = 1;
+-				}
+-			}
+-#endif
+-			if (do_merge)
++			if (do_merge) {
++				/* Lookup the new node if any (this grabs a reference to it) */
++				ni = ieee80211_find_txnode(vap, wh->i_addr2);
++				memcpy(ni->ni_bssid, wh->i_addr3, IEEE80211_ADDR_LEN);
+ 				ieee80211_ibss_merge(ni);
++				ieee80211_unref_node(&ni);
++			}
+ 
+ 			if ((sc->sc_opmode == HAL_M_IBSS) &&
+ 					ath_hw_check_atim(sc, 1, vap->iv_bss->ni_intval))
+@@ -6739,8 +6711,6 @@ ath_recv_mgmt(struct ieee80211vap * vap,
+ 		}
+ 		break;
+ 	}
+-
+-	ieee80211_unref_node(&ni);
+ }
+ 
+ static void
+--- a/net80211/ieee80211_linux.h
++++ b/net80211/ieee80211_linux.h
+@@ -411,7 +411,7 @@ typedef spinlock_t acl_lock_t;
+  *     8 bytes so we reserve/avoid it.
+  */
+ 	struct ieee80211_cb {
+-	u_int8_t vlan[8];			/* reserve for vlan tag info */
++	u_int64_t beacon_tsf;
+ 	struct ieee80211_node *ni;
+ 	u_int32_t flags;
+ #define	M_LINK0		0x01			/* frame needs WEP encryption */
+--- a/net80211/ieee80211_scan_sta.c
++++ b/net80211/ieee80211_scan_sta.c
+@@ -1125,11 +1125,8 @@ adhoc_default_action(struct ieee80211vap
+ 	u_int8_t zeroMacAddr[IEEE80211_ADDR_LEN];
+ 
+ 	memset(&zeroMacAddr, 0, IEEE80211_ADDR_LEN);
+-	if (IEEE80211_ADDR_EQ(se->se_bssid, &zeroMacAddr[0])) {
+-		ieee80211_create_ibss(vap, se->se_chan);
+-		return 1;
+-	} else
+-		return ieee80211_sta_join(vap, se);
++	ieee80211_create_ibss(vap, se->se_chan);
++	return 1;
+ }
+ 
+ static const struct ieee80211_scanner adhoc_default = {
-- 
2.30.2