| Index: server/site_linux_router.py
|
| diff --git a/server/site_linux_router.py b/server/site_linux_router.py
|
| index 4c00c6aa5bb8babcecfb612f98433b8efcc06524..8af74be1efdb34c2cda45564aa806630229d9b9e 100644
|
| --- a/server/site_linux_router.py
|
| +++ b/server/site_linux_router.py
|
| @@ -21,18 +21,26 @@ class LinuxRouter(object):
|
|
|
|
|
| def __init__(self, host, params, defssid):
|
| + # Command locations.
|
| self.cmd_iw = "/usr/sbin/iw"
|
| self.cmd_ip = "/usr/sbin/ip"
|
| self.cmd_brctl = "/usr/sbin/brctl"
|
| self.cmd_hostapd = "/usr/sbin/hostapd"
|
|
|
| + # Router host.
|
| self.router = host
|
| - # default to 1st available wireless nic
|
| +
|
| + # Network interfaces.
|
| + self.bridgeif = params.get('bridgeif', "br-lan")
|
| + self.wiredif = params.get('wiredif', "eth1")
|
| + self.wlanif = "wlan0"
|
| +
|
| + # Default to 1st available wireless phy.
|
| if "phydev" not in params:
|
| output = self.router.run("%s list" % self.cmd_iw).stdout
|
| - wifitest = re.compile("Wiphy (.*)")
|
| + test = re.compile("Wiphy (.*)")
|
| for line in output.splitlines():
|
| - m = wifitest.match(line)
|
| + m = test.match(line)
|
| if m:
|
| self.phydev = m.group(1)
|
| break
|
| @@ -41,12 +49,42 @@ class LinuxRouter(object):
|
| else:
|
| self.phydev = params['phydev']
|
|
|
| - self.hostapd_conf = "/tmp/%s.conf" % self.phydev
|
| - self.hostapd_driver = "nl80211"
|
| - self.phytype = None
|
| - self.bridgeif = params.get("bridgeif", "br-lan")
|
| - self.wlanif = "wlan0"
|
| - self.defssid = defssid;
|
| +
|
| + # hostapd configuration persists throughout the test, subsequent
|
| + # 'config' commands only modify it.
|
| + self.hostapd = {
|
| + 'configured': False,
|
| + 'file': "/tmp/%s.conf" % self.phydev,
|
| + 'driver': "nl80211",
|
| + 'conf': {
|
| + 'ssid': defssid,
|
| + 'interface': self.wlanif,
|
| + 'bridge': self.bridgeif
|
| + }
|
| + }
|
| +
|
| + # Kill hostapd if already running.
|
| + self.router.run("pkill hostapd >/dev/null 2>&1", ignore_status=True)
|
| +
|
| + # Remove all bridges.
|
| + output = self.router.run("%s show" % self.cmd_brctl).stdout
|
| + test = re.compile("^(\S+).*")
|
| + for line in output.splitlines()[1:]:
|
| + m = test.match(line)
|
| + if m:
|
| + device = m.group(1)
|
| + self.router.run("%s link set %s down" % (self.cmd_ip, device))
|
| + self.router.run("%s delbr %s" % (self.cmd_brctl, device))
|
| +
|
| + # Remove all wifi devices.
|
| + output = self.router.run("%s dev" % self.cmd_iw).stdout
|
| + test = re.compile("[\s]*Interface (.*)")
|
| + for line in output.splitlines():
|
| + m = test.match(line)
|
| + if m:
|
| + device = m.group(1)
|
| + self.router.run("%s link set %s down" % (self.cmd_ip, device))
|
| + self.router.run("%s dev %s del" % (self.cmd_iw, device))
|
|
|
|
|
| def create(self, params):
|
| @@ -59,7 +97,7 @@ class LinuxRouter(object):
|
| # map from bsd types to iw types
|
| if params['type'] == "ap" or params['type'] == "hostap":
|
| self.apmode = True
|
| - self.phytype = {
|
| + phytype = {
|
| "sta" : "managed",
|
| "monitor" : "monitor",
|
| "adhoc" : "adhoc",
|
| @@ -71,117 +109,157 @@ class LinuxRouter(object):
|
| }[params['type']]
|
| phydev = params.get('phydev', self.phydev)
|
| self.router.run("%s phy %s interface add %s type %s" %
|
| - (self.cmd_iw, phydev, self.wlanif, self.phytype))
|
| + (self.cmd_iw, phydev, self.wlanif, phytype))
|
| +
|
|
|
|
|
| def destroy(self, params):
|
| """ Destroy a previously created device """
|
| - self.router.run("%s dev %s del" % (self.cmd_iw, self.wlanif))
|
| + # For linux, this is the same as deconfig.
|
| + self.deconfig(params)
|
| +
|
|
|
|
|
| def config(self, params):
|
| """ Configure the AP per test requirements """
|
|
|
| + if self.hostapd['configured']:
|
| + self.deconfig({})
|
| +
|
| if self.apmode:
|
| - # construct the hostapd.conf file and start hostapd
|
| - hostapd_args = ["interface=%s" % self.wlanif]
|
| - hostapd_args.append("bridge=%s" % self.bridgeif)
|
| - hostapd_args.append("driver=%s" %
|
| - params.get("hostapd_driver", self.hostapd_driver))
|
| - if 'ssid' not in params:
|
| - params['ssid'] = self.defssid
|
| - wmm = 0
|
| - htcaps = None
|
| + # Construct the hostapd.conf file and start hostapd.
|
| + conf = self.hostapd['conf']
|
| + htcaps = set()
|
| +
|
| + conf['driver'] = params.get('hostapd_driver', self.hostapd['driver'])
|
| +
|
| for k, v in params.iteritems():
|
| if k == 'ssid':
|
| - hostapd_args.append("ssid=%s" % v)
|
| + conf['ssid'] = v
|
| elif k == 'channel':
|
| freq = int(v)
|
| - if freq >= 2412 and freq <= 2472:
|
| - chan = 1 + (freq - 2412) / 5
|
| - elif freq == 2484:
|
| - chan = 14
|
| - elif freq >= 4915 and freq <= 4980:
|
| - chan = 183 + (freq - 4915) / 5
|
| - elif freq >= 5035 and freq <= 5825:
|
| - chan = 7 + (freq - 5025) / 5
|
| +
|
| + # 2.4GHz
|
| + if freq < 2500:
|
| + if conf['hw_mode'] == 'a':
|
| + conf['hw_mode'] = 'b'
|
| +
|
| + # Freq = 5 * chan + 2407
|
| + if freq >= 2412 and freq <= 2472:
|
| + conf['channel'] = (freq - 2407) / 5
|
| + # Channel 14 is an exception
|
| + elif freq == 2484:
|
| + conf['channel'] = 14
|
| + # 5GHz
|
| else:
|
| - chan = -1
|
| - hostapd_args.append("channel=%s" % chan)
|
| + conf['hw_mode'] = 'a'
|
| + # Freq = 5 * chan + 4000
|
| + if freq >= 4915 and freq <= 4980:
|
| + conf['channel'] = 183 + (freq - 4915) / 5
|
| + # Freq = 5 * chan + 5000
|
| + elif freq >= 5035 and freq <= 5825:
|
| + conf['channel'] = (freq - 5000) / 5
|
| +
|
| elif k == 'country':
|
| - hostapd_args.append("country_code=%s" % v)
|
| + conf['country_code'] = v
|
| elif k == 'dotd':
|
| - hostapd_args.append("ieee80211d=1")
|
| + conf['ieee80211d'] = 1
|
| elif k == '-dotd':
|
| - hostapd_args.append("ieee80211d=0")
|
| + conf['ieee80211d'] = 0
|
| elif k == 'mode':
|
| if v == '11a':
|
| - hostapd_args.append("hw_mode=a")
|
| + conf['hw_mode'] = 'a'
|
| elif v == '11g':
|
| - hostapd_args.append("hw_mode=g")
|
| + conf['hw_mode'] = 'g'
|
| elif v == '11b':
|
| - hostapd_args.append("hw_mode=b")
|
| + conf['hw_mode'] = 'b'
|
| elif v == '11n':
|
| - hostapd_args.append("ieee80211n=1")
|
| + conf['ieee80211n'] = 1
|
| elif k == 'bintval':
|
| - hostapd_args.append("beacon_int=%s" % v)
|
| + conf['beacon_int'] = v
|
| elif k == 'dtimperiod':
|
| - hostapd_args.append("dtim_period=%s" % v)
|
| + conf['dtim_period'] = v
|
| elif k == 'rtsthreshold':
|
| - hostapd_args.append("rts_threshold=%s" % v)
|
| + conf['rts_threshold'] = v
|
| elif k == 'fragthreshold':
|
| - hostapd_args.append("fragm_threshold=%s" % v)
|
| + conf['fragm_threshold'] = v
|
| elif k == 'shortpreamble':
|
| - hostapd_args.append("preamble=1")
|
| + conf['preamble'] = 1
|
| elif k == 'authmode':
|
| - if v == 'open':
|
| - hostapd_args.append("auth_algs=1")
|
| - elif v == 'shared':
|
| - hostapd_args.append("auth_algs=2")
|
| + if v == "open":
|
| + conf['auth_algs'] = 1
|
| + elif v == "shared":
|
| + conf['auth_algs'] = 2
|
| elif k == 'hidessid':
|
| - hostapd_args.append("ignore_broadcast_ssid=1")
|
| + conf['ignore_broadcast_ssid'] = 1
|
| elif k == 'wme':
|
| - wmm = 1;
|
| + conf['wmm_enabled'] = 1
|
| elif k == '-wme':
|
| - wmm = 0;
|
| + conf['wmm_enabled'] = 0
|
| elif k == 'deftxkey':
|
| - hostapd_args.append("wep_default_key=%s" % v)
|
| + conf['wep_default_key'] = v
|
| elif k == 'ht20':
|
| - htcaps.append("")
|
| - wmm = 1;
|
| + conf['wmm_enabled'] = 1
|
| elif k == 'ht40':
|
| - htcaps.append("[HT40-][HT40+]")
|
| - wmm = 1
|
| -# XXX no support elif k == 'rifs':
|
| + htcaps.add('[HT40-]')
|
| + htcaps.add('[HT40+]')
|
| + conf['wmm_enabled'] = 1
|
| elif k == 'shortgi':
|
| - htcaps.append("[SHORT-GI-20][SHORT-GI-40]")
|
| + htcaps.add('[SHORT-GI-20]')
|
| + htcaps.add('[SHORT-GI-40]')
|
| + elif k == 'pureg' or k == 'puren' or k == 'wepmode' or k == 'rifs':
|
| + # no support
|
| + pass
|
| else:
|
| - hostapd_args.append("%s=%s" % (k, v))
|
| + conf[k] = v
|
|
|
| - if htcaps is not None:
|
| - hostapd_args.append("ieee80211n=1")
|
| - hostapd_args.append("ht_capab=%s" % htcaps)
|
| - hostapd_args.append("wmm_enabled=%d" % wmm)
|
| + # Aggregate ht_capab.
|
| + if htcaps:
|
| + conf['ieee80211n'] = 1
|
| + conf['ht_capab'] = ''.join(htcaps)
|
|
|
| + # Generate hostapd.conf.
|
| self.router.run("cat <<EOF >%s\n%s\nEOF\n" %
|
| - (self.hostapd_conf, "\n".join(hostapd_args)))
|
| + (self.hostapd['file'], '\n'.join(
|
| + "%s=%s" % kv for kv in conf.iteritems())))
|
| +
|
| + # Run hostapd.
|
| self.router.run("%s -B %s" %
|
| - (self.cmd_hostapd, self.hostapd_conf))
|
| + (self.cmd_hostapd, self.hostapd['file']))
|
| +
|
| + # Set up the bridge.
|
| + self.router.run("%s setfd %s %d" %
|
| + (self.cmd_brctl, self.bridgeif, 0))
|
| + self.router.run("%s addif %s %s" %
|
| + (self.cmd_brctl, self.bridgeif, self.wiredif))
|
| + self.router.run("%s link set %s up" %
|
| + (self.cmd_ip, self.wiredif))
|
| + self.router.run("%s link set %s up" %
|
| + (self.cmd_ip, self.bridgeif))
|
|
|
| # else:
|
| # # use iw to manually configure interface
|
|
|
| + self.hostapd['configured'] = True
|
|
|
|
|
| def deconfig(self, params):
|
| - """ De-configure the AP (typically marks wlanif down) """
|
| + """ De-configure the AP (will also bring wlan and the bridge down) """
|
| +
|
| + if not self.hostapd['configured']:
|
| + return
|
| +
|
| + # Taking down hostapd takes wlan0 and mon.wlan0 down.
|
| + self.router.run("pkill hostapd >/dev/null 2>&1", ignore_status=True)
|
| +# self.router.run("rm -f %s" % self.hostapd['file'])
|
|
|
| - self.router.run("%s link set %s down" % (self.cmd_ip, self.wlanif))
|
| - if self.hostapd_conf is not None:
|
| - self.router.run("pkill hostapd >/dev/null 2>&1")
|
| - self.router.run("rm -f %s" % self.hostapd_conf)
|
| - self.hostapd_conf = None
|
| + # Tear down the bridge.
|
| + self.router.run("%s link set %s down" % (self.cmd_ip, self.bridgeif),
|
| + ignore_status=True)
|
| + self.router.run("%s delbr %s" % (self.cmd_brctl, self.bridgeif),
|
| + ignore_status=True)
|
|
|
| + self.hostapd['configured'] = False
|
|
|
| def client_check_config(self, params):
|
| """
|
|
|