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