802.11n -> 802.11ac AP-Client Kick-Off Script (Py)

So I have been running multiple APs with the same SSID on separate channels and frequencies and noticed that the clients are really good at switching from a weak 802.11ac signal strength to the stronger but lower speed 802.11n AP station. This is good, however, they don’t seem to be as aggressive in switching back to 802.11ac once they get closer again (unless they turn off or shutdown or restart their network stack since the 802.11n just gets stronger the closer you get). I found an OpenWRT compatible shell script which kicks clients off a given radio depending on their signal strength to the router. I adjusted it to disconnect a client if they start to get too close to the N router as they are likely going to get a good signal strength from the AC AP instead. You can set the AP deauth time (ex 19 seconds), the time between kicking the same client on/off again (ex 31 mins), and it checks for the signal-to-noise ratio to get above a certain amount (ex 45 SNR) before activating on a client!

python apc.py n 20 40
import os,sys,time

radios = []
mode = sys.argv[1]
secs = (int(sys.argv[2]) * 1000)
macs = {}
band = (int(sys.argv[3]) * 60)

if (mode == "ac"):
	radios = ["wlan0"]

if (mode == "n"):
	radios = ["wlan1"]

while True:
	sec = int(time.time())

	for intf in radios:
		os.system("iwinfo '%s' assoclist | grep 'SNR' | tr '(/)' ' ' | tr -s ' ' > /tmp/apc.log" % (intf))
		f = open("/tmp/apc.log", "r")
		lines = f.readlines()
		f.close()

		for line in lines:
			info = line.strip().split(" ")
			(mac, sig, snr) = (info[0], int(info[1]), abs(int(info[6])))
			print("> %d %d [%s][%s]" % (snr, sig, intf, mac))

			if (secs >= 1000):
				delc = 0 ; kick = "true"
				opts = ("'addr':'%s', 'reason':5, 'deauth':%s, 'ban_time':%s" % (mac, kick, secs))

				if ((mode == "ac") and (sig <= -83)):
					delc = 1

				#if ((mode == "n") and (sig >= -51)):
				#	delc = 1

				if ((mode == "n") and (snr >= 45)):
					delc = 1

				if (delc == 1):
					if (not mac in macs.keys()):
						macs[mac] = 0
					if (sec >= (macs[mac] + band)):
						macs[mac] = sec
						print("* %d %d [%s][%s][%d][%d]" % (macs[mac], sec, mac, intf, sig, snr))
						os.system('ubus call "hostapd.%s" del_client "{%s}"' % (intf, opts))

	for mac in macs.keys():
		if (sec >= (macs[mac] + band)):
			print("x", mac, macs[mac])
			del macs[mac]

	print("")
	time.sleep(9)

Leave a comment