From c0dc50fb550a7e5ceaeacd48fca27069958832c9 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@openwrt.org>
Date: Fri, 25 Jul 2008 22:36:33 +0000
Subject: [PATCH] rewrite madwifi sta mode link up/down notifications (mostly
 used by wpa_supplicant), fixes some stale node or reconnect loop issues

SVN-Revision: 11926
---
 package/madwifi/patches/360-sta_nodes.patch | 202 +++++++++++++++++++-
 1 file changed, 197 insertions(+), 5 deletions(-)

diff --git a/package/madwifi/patches/360-sta_nodes.patch b/package/madwifi/patches/360-sta_nodes.patch
index 4f70b5712d..e701f9069b 100644
--- a/package/madwifi/patches/360-sta_nodes.patch
+++ b/package/madwifi/patches/360-sta_nodes.patch
@@ -14,7 +14,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
  				break;
  			case IEEE80211_M_HOSTAP:
  				ieee80211_iterate_nodes(&ic->ic_sta,
-@@ -1358,6 +1358,7 @@
+@@ -1358,12 +1358,14 @@
  				break;
  			}
  			goto reset;
@@ -22,7 +22,14 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
  		case IEEE80211_S_ASSOC:
  			switch (vap->iv_opmode) {
  			case IEEE80211_M_STA:
-@@ -1376,7 +1377,6 @@
+ 				IEEE80211_SEND_MGMT(ni,
+ 					IEEE80211_FC0_SUBTYPE_DEAUTH,
+ 					IEEE80211_REASON_AUTH_LEAVE);
++				ieee80211_node_leave(ni);
+ 				break;
+ 			case IEEE80211_M_HOSTAP:
+ 				ieee80211_iterate_nodes(&ic->ic_sta,
+@@ -1376,7 +1378,6 @@
  		case IEEE80211_S_SCAN:
  			ieee80211_cancel_scan(vap);
  			goto reset;
@@ -30,7 +37,12 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
  		reset:
  			ieee80211_reset_bss(vap);
  			break;
-@@ -1432,7 +1432,7 @@
+@@ -1429,10 +1430,12 @@
+ 					IEEE80211_SCAN_FOREVER,
+ 					vap->iv_des_nssid, vap->iv_des_ssid,
+ 					NULL);
++			else
++				ieee80211_node_leave(vap->iv_bss);
  			break;
  		case IEEE80211_S_RUN:		/* beacon miss */
  			if (vap->iv_opmode == IEEE80211_M_STA) {
@@ -39,7 +51,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
  				vap->iv_flags &= ~IEEE80211_F_SIBSS;	/* XXX */
  				if (ic->ic_roaming == IEEE80211_ROAMING_AUTO)
  					ieee80211_check_scan(vap,
-@@ -1483,7 +1483,7 @@
+@@ -1484,7 +1487,7 @@
  				vap->iv_state = ostate;	/* stay RUN */
  				break;
  			case IEEE80211_FC0_SUBTYPE_DEAUTH:
@@ -48,7 +60,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
  				if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) {
  					/* try to reauth */
  					IEEE80211_SEND_MGMT(ni,
-@@ -1510,7 +1510,7 @@
+@@ -1511,7 +1514,7 @@
  				IEEE80211_FC0_SUBTYPE_ASSOC_REQ, 0);
  			break;
  		case IEEE80211_S_RUN:
@@ -57,3 +69,183 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
  			if (ic->ic_roaming == IEEE80211_ROAMING_AUTO) {
  				/* NB: caller specifies ASSOC/REASSOC by arg */
  				IEEE80211_SEND_MGMT(ni, arg ?
+@@ -1779,6 +1782,7 @@
+ 			  ieee80211_state_name[nstate], 
+ 			  ieee80211_state_name[dstate]);
+ 
++	ieee80211_update_link_status(vap, nstate, ostate);
+ 	switch (nstate) {
+ 	case IEEE80211_S_AUTH:
+ 	case IEEE80211_S_ASSOC:
+--- a/net80211/ieee80211_linux.c
++++ b/net80211/ieee80211_linux.c
+@@ -233,33 +233,59 @@
+ }
+ 
+ void
+-ieee80211_notify_node_join(struct ieee80211_node *ni, int newassoc)
++ieee80211_update_link_status(struct ieee80211vap *vap, int nstate, int ostate)
+ {
+-	struct ieee80211vap *vap = ni->ni_vap;
+ 	struct net_device *dev = vap->iv_dev;
+ 	union iwreq_data wreq;
++	int active;
++
++	if (vap->iv_opmode != IEEE80211_M_STA)
++		return;
++
++	if (ostate == nstate)
++		return;
++
++	if (nstate == IEEE80211_S_RUN)
++		active = 1;
++	else if ((ostate >= IEEE80211_S_AUTH) && (nstate < ostate))
++		active = 0;
++	else
++		return;
++
++	if (active && !vap->iv_bss)
++		return;
++
++	memset(&wreq, 0, sizeof(wreq));
++	wreq.ap_addr.sa_family = ARPHRD_ETHER;
+ 
+-	if (ni == vap->iv_bss) {
+-		if (newassoc)
+-			netif_carrier_on(dev);
+-		memset(&wreq, 0, sizeof(wreq));
++	if (active) {
++		//netif_carrier_on(vap->iv_dev);
+ 		IEEE80211_ADDR_COPY(wreq.addr.sa_data, vap->iv_bssid);
+-		wreq.addr.sa_family = ARPHRD_ETHER;
+-#ifdef ATH_SUPERG_XR
+-		if (vap->iv_xrvap && vap->iv_flags & IEEE80211_F_XR)
+-			dev = vap->iv_xrvap->iv_dev;
+-#endif
+-		wireless_send_event(dev, SIOCGIWAP, &wreq, NULL);
+ 	} else {
+-		memset(&wreq, 0, sizeof(wreq));
+-		IEEE80211_ADDR_COPY(wreq.addr.sa_data, ni->ni_macaddr);
+-		wreq.addr.sa_family = ARPHRD_ETHER;
++		//netif_carrier_off(vap->iv_dev);
++		memset(wreq.ap_addr.sa_data, 0, ETHER_ADDR_LEN);
++	}
++	wireless_send_event(dev, SIOCGIWAP, &wreq, NULL);
++}
++
++void
++ieee80211_notify_node_join(struct ieee80211_node *ni, int newassoc)
++{
++	struct ieee80211vap *vap = ni->ni_vap;
++	struct net_device *dev = vap->iv_dev;
++	union iwreq_data wreq;
++
++	if (ni == vap->iv_bss)
++		return;
++
++	memset(&wreq, 0, sizeof(wreq));
++	IEEE80211_ADDR_COPY(wreq.addr.sa_data, ni->ni_macaddr);
++	wreq.addr.sa_family = ARPHRD_ETHER;
+ #ifdef ATH_SUPERG_XR
+-		if (vap->iv_xrvap && vap->iv_flags & IEEE80211_F_XR)
+-			dev = vap->iv_xrvap->iv_dev;
++	if (vap->iv_xrvap && vap->iv_flags & IEEE80211_F_XR)
++		dev = vap->iv_xrvap->iv_dev;
+ #endif
+-		wireless_send_event(dev, IWEVREGISTERED, &wreq, NULL);
+-	}
++	wireless_send_event(dev, IWEVREGISTERED, &wreq, NULL);
+ }
+ 
+ void
+@@ -269,18 +295,14 @@
+ 	struct net_device *dev = vap->iv_dev;
+ 	union iwreq_data wreq;
+ 
+-	if (ni == vap->iv_bss) {
+-		netif_carrier_off(dev);
+-		memset(wreq.ap_addr.sa_data, 0, ETHER_ADDR_LEN);
+-		wreq.ap_addr.sa_family = ARPHRD_ETHER;
+-		wireless_send_event(dev, SIOCGIWAP, &wreq, NULL);
+-	} else {
+-		/* fire off wireless event station leaving */
+-		memset(&wreq, 0, sizeof(wreq));
+-		IEEE80211_ADDR_COPY(wreq.addr.sa_data, ni->ni_macaddr);
+-		wreq.addr.sa_family = ARPHRD_ETHER;
+-		wireless_send_event(dev, IWEVEXPIRED, &wreq, NULL);
+-	}
++	if (ni == vap->iv_bss)
++		return;
++
++	/* fire off wireless event station leaving */
++	memset(&wreq, 0, sizeof(wreq));
++	IEEE80211_ADDR_COPY(wreq.addr.sa_data, ni->ni_macaddr);
++	wreq.addr.sa_family = ARPHRD_ETHER;
++	wireless_send_event(dev, IWEVEXPIRED, &wreq, NULL);
+ }
+ 
+ void
+--- a/net80211/ieee80211_node.c
++++ b/net80211/ieee80211_node.c
+@@ -2332,6 +2332,7 @@
+ 		count_suppchans(ic, ni, -1);
+ 	IEEE80211_UNLOCK_IRQ(ic);
+ 
++done:
+ 	/*
+ 	 * Cleanup station state.  In particular clear various
+ 	 * state that might otherwise be reused if the node
+@@ -2339,7 +2340,7 @@
+ 	 * (and memory is reclaimed).
+ 	 */
+ 	ieee80211_sta_leave(ni);
+-done:
++
+ 	/* Run a cleanup */
+ #ifdef IEEE80211_DEBUG_REFCNT
+ 	ic->ic_node_cleanup_debug(ni, __func__, __LINE__);
+--- a/net80211/ieee80211_node.h
++++ b/net80211/ieee80211_node.h
+@@ -60,7 +60,7 @@
+ #define	IEEE80211_INACT_PROBE	(30/IEEE80211_INACT_WAIT)	/* probe */
+ #define	IEEE80211_INACT_SCAN	(300/IEEE80211_INACT_WAIT)	/* scanned */
+ 
+-#define	IEEE80211_TRANS_WAIT 	5				/* mgt frame tx timer (secs) */
++#define	IEEE80211_TRANS_WAIT	300				/* mgt frame tx timer (msecs) */
+ 
+ #define	IEEE80211_NODE_HASHSIZE	32
+ /* simple hash is enough for variation of macaddr */
+--- a/net80211/ieee80211_output.c
++++ b/net80211/ieee80211_output.c
+@@ -2140,7 +2140,7 @@
+ 
+ 	ieee80211_mgmt_output(ieee80211_ref_node(ni), skb, type);
+ 	if (timer)
+-		mod_timer(&vap->iv_mgtsend, jiffies + timer * HZ);
++		mod_timer(&vap->iv_mgtsend, jiffies + msecs_to_jiffies(timer));
+ 	return 0;
+ bad:
+ 	return ret;
+--- a/net80211/ieee80211_wireless.c
++++ b/net80211/ieee80211_wireless.c
+@@ -514,8 +514,9 @@
+ 			vap->iv_flags |= IEEE80211_F_DESBSSID;
+ 
+ 		IEEE80211_ADDR_COPY(vap->iv_des_bssid, &ap_addr->sa_data);
+-		if (IS_UP_AUTO(vap))
++		if (IS_UP(vap->iv_dev)) {
+ 			ieee80211_new_state(vap, IEEE80211_S_SCAN, 0);
++		}
+ 	}
+ 	return 0;
+ }
+--- a/net80211/ieee80211_linux.h
++++ b/net80211/ieee80211_linux.h
+@@ -643,6 +643,7 @@
+ #define	free_netdev(dev)	kfree(dev)
+ #endif
+ 
++void ieee80211_update_link_status(struct ieee80211vap *vap, int nstate, int ostate);
+ void ieee80211_ioctl_vattach(struct ieee80211vap *);
+ void ieee80211_ioctl_vdetach(struct ieee80211vap *);
+ struct ifreq;
-- 
GitLab