Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 1 | # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 2 | # Use of this source code is governed by a BSD-style license that can be |
| 3 | # found in the LICENSE file. |
| 4 | |
Sam Leffler | 19bb0a7 | 2010-04-12 08:51:08 -0700 | [diff] [blame^] | 5 | import re |
| 6 | |
| 7 | def isLinuxRouter(router): |
| 8 | router_uname = router.run('uname').stdout |
| 9 | return re.search('Linux', router_uname) |
| 10 | |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 11 | class LinuxRouter(object): |
| 12 | """ |
| 13 | Linux/mac80211-style WiFi Router support for WiFiTest class. |
| 14 | |
| 15 | This class implements test methods/steps that communicate with a |
| 16 | router implemented with Linux/mac80211. The router must |
| 17 | be pre-configured to enable ssh access and have a mac80211-based |
| 18 | wireless device. We also assume hostapd 0.7.x and iw are present |
| 19 | and any necessary modules are pre-loaded. |
| 20 | """ |
| 21 | |
| 22 | |
| 23 | def __init__(self, host, params, defssid): |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 24 | self.cmd_iw = "/usr/sbin/iw" |
| 25 | self.cmd_ip = "/usr/sbin/ip" |
| 26 | self.cmd_brctl = "/usr/sbin/brctl" |
| 27 | self.cmd_hostapd = "/usr/sbin/hostapd" |
| 28 | |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 29 | self.router = host |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 30 | # default to 1st available wireless nic |
| 31 | if "phydev" not in params: |
| 32 | output = self.router.run("%s list" % self.cmd_iw).stdout |
| 33 | wifitest = re.compile("Wiphy (.*)") |
| 34 | for line in output.splitlines(): |
| 35 | m = wifitest.match(line) |
| 36 | if m: |
| 37 | self.phydev = m.group(1) |
| 38 | break |
| 39 | else: |
| 40 | raise Exception("No Wireless NIC detected on the device") |
| 41 | else: |
| 42 | self.phydev = params['phydev'] |
| 43 | |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 44 | self.hostapd_conf = "/tmp/%s.conf" % self.phydev |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 45 | self.hostapd_driver = "nl80211" |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 46 | self.phytype = None |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 47 | self.bridgeif = params.get("bridgeif", "br-lan") |
| 48 | self.wlanif = "wlan0" |
| 49 | self.defssid = defssid; |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 50 | |
| 51 | |
| 52 | def create(self, params): |
| 53 | """ Create a wifi device of the specified type """ |
| 54 | # |
| 55 | # AP mode is handled entirely by hostapd so we only |
| 56 | # have to setup others (mapping the bsd type to what |
| 57 | # iw wants) |
| 58 | # |
| 59 | # map from bsd types to iw types |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 60 | if params['type'] == "ap" or params['type'] == "hostap": |
| 61 | self.apmode = True |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 62 | self.phytype = { |
| 63 | "sta" : "managed", |
| 64 | "monitor" : "monitor", |
| 65 | "adhoc" : "adhoc", |
| 66 | "ibss" : "ibss", |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 67 | "ap" : "managed", # NB: handled by hostapd |
| 68 | "hostap" : "managed", # NB: handled by hostapd |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 69 | "mesh" : "mesh", |
| 70 | "wds" : "wds", |
| 71 | }[params['type']] |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 72 | phydev = params.get('phydev', self.phydev) |
| 73 | self.router.run("%s phy %s interface add %s type %s" % |
| 74 | (self.cmd_iw, phydev, self.wlanif, self.phytype)) |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 75 | |
| 76 | |
| 77 | def destroy(self, params): |
| 78 | """ Destroy a previously created device """ |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 79 | self.router.run("%s dev %s del" % (self.cmd_iw, self.wlanif)) |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 80 | |
| 81 | |
| 82 | def config(self, params): |
| 83 | """ Configure the AP per test requirements """ |
| 84 | |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 85 | if self.apmode: |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 86 | # construct the hostapd.conf file and start hostapd |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 87 | hostapd_args = ["interface=%s" % self.wlanif] |
| 88 | hostapd_args.append("bridge=%s" % self.bridgeif) |
| 89 | hostapd_args.append("driver=%s" % |
| 90 | params.get("hostapd_driver", self.hostapd_driver)) |
| 91 | if 'ssid' not in params: |
| 92 | params['ssid'] = self.defssid |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 93 | wmm = 0 |
| 94 | htcaps = None |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 95 | for k, v in params.iteritems(): |
| 96 | if k == 'ssid': |
| 97 | hostapd_args.append("ssid=%s" % v) |
| 98 | elif k == 'channel': |
| 99 | freq = int(v) |
| 100 | if freq >= 2412 and freq <= 2472: |
| 101 | chan = 1 + (freq - 2412) / 5 |
| 102 | elif freq == 2484: |
| 103 | chan = 14 |
| 104 | elif freq >= 4915 and freq <= 4980: |
| 105 | chan = 183 + (freq - 4915) / 5 |
| 106 | elif freq >= 5035 and freq <= 5825: |
| 107 | chan = 7 + (freq - 5025) / 5 |
| 108 | else: |
| 109 | chan = -1 |
| 110 | hostapd_args.append("channel=%s" % chan) |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 111 | elif k == 'country': |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 112 | hostapd_args.append("country_code=%s" % v) |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 113 | elif k == 'dotd': |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 114 | hostapd_args.append("ieee80211d=1") |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 115 | elif k == '-dotd': |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 116 | hostapd_args.append("ieee80211d=0") |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 117 | elif k == 'mode': |
| 118 | if v == '11a': |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 119 | hostapd_args.append("hw_mode=a") |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 120 | elif v == '11g': |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 121 | hostapd_args.append("hw_mode=g") |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 122 | elif v == '11b': |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 123 | hostapd_args.append("hw_mode=b") |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 124 | elif v == '11n': |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 125 | hostapd_args.append("ieee80211n=1") |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 126 | elif k == 'bintval': |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 127 | hostapd_args.append("beacon_int=%s" % v) |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 128 | elif k == 'dtimperiod': |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 129 | hostapd_args.append("dtim_period=%s" % v) |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 130 | elif k == 'rtsthreshold': |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 131 | hostapd_args.append("rts_threshold=%s" % v) |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 132 | elif k == 'fragthreshold': |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 133 | hostapd_args.append("fragm_threshold=%s" % v) |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 134 | elif k == 'shortpreamble': |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 135 | hostapd_args.append("preamble=1") |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 136 | elif k == 'authmode': |
| 137 | if v == 'open': |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 138 | hostapd_args.append("auth_algs=1") |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 139 | elif v == 'shared': |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 140 | hostapd_args.append("auth_algs=2") |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 141 | elif k == 'hidessid': |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 142 | hostapd_args.append("ignore_broadcast_ssid=1") |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 143 | elif k == 'wme': |
| 144 | wmm = 1; |
| 145 | elif k == '-wme': |
| 146 | wmm = 0; |
| 147 | elif k == 'deftxkey': |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 148 | hostapd_args.append("wep_default_key=%s" % v) |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 149 | elif k == 'ht20': |
| 150 | htcaps.append("") |
| 151 | wmm = 1; |
| 152 | elif k == 'ht40': |
| 153 | htcaps.append("[HT40-][HT40+]") |
| 154 | wmm = 1 |
| 155 | # XXX no support elif k == 'rifs': |
| 156 | elif k == 'shortgi': |
| 157 | htcaps.append("[SHORT-GI-20][SHORT-GI-40]") |
| 158 | else: |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 159 | hostapd_args.append("%s=%s" % (k, v)) |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 160 | |
| 161 | if htcaps is not None: |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 162 | hostapd_args.append("ieee80211n=1") |
| 163 | hostapd_args.append("ht_capab=%s" % htcaps) |
| 164 | hostapd_args.append("wmm_enabled=%d" % wmm) |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 165 | |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 166 | self.router.run("cat <<EOF >%s\n%s\nEOF\n" % |
| 167 | (self.hostapd_conf, "\n".join(hostapd_args))) |
| 168 | self.router.run("%s -B %s" % |
| 169 | (self.cmd_hostapd, self.hostapd_conf)) |
| 170 | |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 171 | # else: |
| 172 | # # use iw to manually configure interface |
| 173 | |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 174 | |
| 175 | |
| 176 | def deconfig(self, params): |
| 177 | """ De-configure the AP (typically marks wlanif down) """ |
| 178 | |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 179 | self.router.run("%s link set %s down" % (self.cmd_ip, self.wlanif)) |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 180 | if self.hostapd_conf is not None: |
| 181 | self.router.run("pkill hostapd >/dev/null 2>&1") |
| 182 | self.router.run("rm -f %s" % self.hostapd_conf) |
| 183 | self.hostapd_conf = None |
| 184 | |
| 185 | |
| 186 | def client_check_config(self, params): |
| 187 | """ |
| 188 | Check network configuration on client to verify parameters |
| 189 | have been negotiated during the connection to the router. |
| 190 | """ |
| 191 | # XXX fill in |