blob: 26c18ea238498cd7493f591dbdb49e2bf9285538 [file] [log] [blame]
Sam Leffler6969d1d2010-03-15 16:07:11 -07001# 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 Leffler19bb0a72010-04-12 08:51:08 -07005import re
6
7def isLinuxRouter(router):
8 router_uname = router.run('uname').stdout
9 return re.search('Linux', router_uname)
10
Sam Leffler6969d1d2010-03-15 16:07:11 -070011class 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 Sabovic4cc2ce92010-04-21 15:08:01 -070024 # Command locations.
Nebojsa Sabovic138ff912010-04-06 15:47:42 -070025 self.cmd_iw = "/usr/sbin/iw"
26 self.cmd_ip = "/usr/sbin/ip"
27 self.cmd_brctl = "/usr/sbin/brctl"
28 self.cmd_hostapd = "/usr/sbin/hostapd"
29
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -070030 # Router host.
Sam Leffler6969d1d2010-03-15 16:07:11 -070031 self.router = host
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -070032
33 # Network interfaces.
Nebojsa Sabovic36c10e92010-04-28 12:37:20 -070034 self.bridgeif = params.get('bridgedev', "br-lan")
35 self.wiredif = params.get('wiredev', "eth1")
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -070036 self.wlanif = "wlan0"
37
38 # Default to 1st available wireless phy.
Nebojsa Sabovic138ff912010-04-06 15:47:42 -070039 if "phydev" not in params:
40 output = self.router.run("%s list" % self.cmd_iw).stdout
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -070041 test = re.compile("Wiphy (.*)")
Nebojsa Sabovic138ff912010-04-06 15:47:42 -070042 for line in output.splitlines():
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -070043 m = test.match(line)
Nebojsa Sabovic138ff912010-04-06 15:47:42 -070044 if m:
45 self.phydev = m.group(1)
46 break
47 else:
Nebojsa Sabovicbae8fd42010-04-23 13:47:23 -070048 raise error.TestFail("No Wireless NIC detected on the device")
Nebojsa Sabovic138ff912010-04-06 15:47:42 -070049 else:
50 self.phydev = params['phydev']
51
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -070052
53 # hostapd configuration persists throughout the test, subsequent
54 # 'config' commands only modify it.
55 self.hostapd = {
56 'configured': False,
57 'file': "/tmp/%s.conf" % self.phydev,
58 'driver': "nl80211",
59 'conf': {
60 'ssid': defssid,
61 'interface': self.wlanif,
62 'bridge': self.bridgeif
63 }
64 }
65
66 # Kill hostapd if already running.
67 self.router.run("pkill hostapd >/dev/null 2>&1", ignore_status=True)
68
69 # Remove all bridges.
70 output = self.router.run("%s show" % self.cmd_brctl).stdout
71 test = re.compile("^(\S+).*")
72 for line in output.splitlines()[1:]:
73 m = test.match(line)
74 if m:
75 device = m.group(1)
76 self.router.run("%s link set %s down" % (self.cmd_ip, device))
77 self.router.run("%s delbr %s" % (self.cmd_brctl, device))
78
79 # Remove all wifi devices.
80 output = self.router.run("%s dev" % self.cmd_iw).stdout
81 test = re.compile("[\s]*Interface (.*)")
82 for line in output.splitlines():
83 m = test.match(line)
84 if m:
85 device = m.group(1)
86 self.router.run("%s link set %s down" % (self.cmd_ip, device))
87 self.router.run("%s dev %s del" % (self.cmd_iw, device))
Sam Leffler6969d1d2010-03-15 16:07:11 -070088
Nebojsa Sabovicbc245c62010-04-28 16:58:50 -070089 # Place us in the US by default
90 self.router.run("%s reg set US" % self.cmd_iw)
Sam Leffler6969d1d2010-03-15 16:07:11 -070091
92 def create(self, params):
93 """ Create a wifi device of the specified type """
94 #
95 # AP mode is handled entirely by hostapd so we only
96 # have to setup others (mapping the bsd type to what
97 # iw wants)
98 #
99 # map from bsd types to iw types
Nebojsa Sabovic138ff912010-04-06 15:47:42 -0700100 if params['type'] == "ap" or params['type'] == "hostap":
101 self.apmode = True
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700102 phytype = {
Sam Leffler6969d1d2010-03-15 16:07:11 -0700103 "sta" : "managed",
104 "monitor" : "monitor",
105 "adhoc" : "adhoc",
106 "ibss" : "ibss",
Nebojsa Sabovic138ff912010-04-06 15:47:42 -0700107 "ap" : "managed", # NB: handled by hostapd
108 "hostap" : "managed", # NB: handled by hostapd
Sam Leffler6969d1d2010-03-15 16:07:11 -0700109 "mesh" : "mesh",
110 "wds" : "wds",
111 }[params['type']]
Nebojsa Sabovic138ff912010-04-06 15:47:42 -0700112 phydev = params.get('phydev', self.phydev)
113 self.router.run("%s phy %s interface add %s type %s" %
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700114 (self.cmd_iw, phydev, self.wlanif, phytype))
115
Sam Leffler6969d1d2010-03-15 16:07:11 -0700116
117
118 def destroy(self, params):
119 """ Destroy a previously created device """
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700120 # For linux, this is the same as deconfig.
121 self.deconfig(params)
122
Sam Leffler6969d1d2010-03-15 16:07:11 -0700123
124
125 def config(self, params):
126 """ Configure the AP per test requirements """
127
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700128 if self.hostapd['configured']:
129 self.deconfig({})
130
Nebojsa Sabovic138ff912010-04-06 15:47:42 -0700131 if self.apmode:
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700132 # Construct the hostapd.conf file and start hostapd.
133 conf = self.hostapd['conf']
134 htcaps = set()
135
Nebojsa Sabovicbae8fd42010-04-23 13:47:23 -0700136 conf['driver'] = params.get('hostapd_driver',
137 self.hostapd['driver'])
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700138
Nebojsa Sabovic138ff912010-04-06 15:47:42 -0700139 for k, v in params.iteritems():
140 if k == 'ssid':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700141 conf['ssid'] = v
Nebojsa Sabovic138ff912010-04-06 15:47:42 -0700142 elif k == 'channel':
143 freq = int(v)
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700144
145 # 2.4GHz
146 if freq < 2500:
Nebojsa Sabovic36c10e92010-04-28 12:37:20 -0700147 # Make sure hw_mode is set
148 if conf.get('hw_mode') == 'a':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700149 conf['hw_mode'] = 'b'
150
151 # Freq = 5 * chan + 2407
152 if freq >= 2412 and freq <= 2472:
153 conf['channel'] = (freq - 2407) / 5
154 # Channel 14 is an exception
155 elif freq == 2484:
156 conf['channel'] = 14
157 # 5GHz
Nebojsa Sabovic138ff912010-04-06 15:47:42 -0700158 else:
Nebojsa Sabovic36c10e92010-04-28 12:37:20 -0700159 # Make sure hw_mode is set
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700160 conf['hw_mode'] = 'a'
161 # Freq = 5 * chan + 4000
162 if freq >= 4915 and freq <= 4980:
Nebojsa Sabovicbc245c62010-04-28 16:58:50 -0700163 conf['channel'] = (freq - 4000) / 5
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700164 # Freq = 5 * chan + 5000
165 elif freq >= 5035 and freq <= 5825:
166 conf['channel'] = (freq - 5000) / 5
167
Sam Leffler6969d1d2010-03-15 16:07:11 -0700168 elif k == 'country':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700169 conf['country_code'] = v
Sam Leffler6969d1d2010-03-15 16:07:11 -0700170 elif k == 'dotd':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700171 conf['ieee80211d'] = 1
Sam Leffler6969d1d2010-03-15 16:07:11 -0700172 elif k == '-dotd':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700173 conf['ieee80211d'] = 0
Sam Leffler6969d1d2010-03-15 16:07:11 -0700174 elif k == 'mode':
175 if v == '11a':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700176 conf['hw_mode'] = 'a'
Sam Leffler6969d1d2010-03-15 16:07:11 -0700177 elif v == '11g':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700178 conf['hw_mode'] = 'g'
Sam Leffler6969d1d2010-03-15 16:07:11 -0700179 elif v == '11b':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700180 conf['hw_mode'] = 'b'
Sam Leffler6969d1d2010-03-15 16:07:11 -0700181 elif v == '11n':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700182 conf['ieee80211n'] = 1
Sam Leffler6969d1d2010-03-15 16:07:11 -0700183 elif k == 'bintval':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700184 conf['beacon_int'] = v
Sam Leffler6969d1d2010-03-15 16:07:11 -0700185 elif k == 'dtimperiod':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700186 conf['dtim_period'] = v
Sam Leffler6969d1d2010-03-15 16:07:11 -0700187 elif k == 'rtsthreshold':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700188 conf['rts_threshold'] = v
Sam Leffler6969d1d2010-03-15 16:07:11 -0700189 elif k == 'fragthreshold':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700190 conf['fragm_threshold'] = v
Sam Leffler6969d1d2010-03-15 16:07:11 -0700191 elif k == 'shortpreamble':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700192 conf['preamble'] = 1
Sam Leffler6969d1d2010-03-15 16:07:11 -0700193 elif k == 'authmode':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700194 if v == "open":
195 conf['auth_algs'] = 1
196 elif v == "shared":
197 conf['auth_algs'] = 2
Sam Leffler6969d1d2010-03-15 16:07:11 -0700198 elif k == 'hidessid':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700199 conf['ignore_broadcast_ssid'] = 1
Sam Leffler6969d1d2010-03-15 16:07:11 -0700200 elif k == 'wme':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700201 conf['wmm_enabled'] = 1
Sam Leffler6969d1d2010-03-15 16:07:11 -0700202 elif k == '-wme':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700203 conf['wmm_enabled'] = 0
Sam Leffler6969d1d2010-03-15 16:07:11 -0700204 elif k == 'deftxkey':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700205 conf['wep_default_key'] = v
Sam Leffler6969d1d2010-03-15 16:07:11 -0700206 elif k == 'ht20':
Nebojsa Sabovic36c10e92010-04-28 12:37:20 -0700207 htcaps.add('') # NB: ensure 802.11n setup below
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700208 conf['wmm_enabled'] = 1
Sam Leffler6969d1d2010-03-15 16:07:11 -0700209 elif k == 'ht40':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700210 htcaps.add('[HT40-]')
211 htcaps.add('[HT40+]')
212 conf['wmm_enabled'] = 1
Sam Leffler6969d1d2010-03-15 16:07:11 -0700213 elif k == 'shortgi':
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700214 htcaps.add('[SHORT-GI-20]')
215 htcaps.add('[SHORT-GI-40]')
Nebojsa Sabovic36c10e92010-04-28 12:37:20 -0700216 elif k == 'pureg':
217 pass # TODO(sleffler) need hostapd support
218 elif k == 'puren':
219 pass # TODO(sleffler) need hostapd support
Nebojsa Sabovicbc245c62010-04-28 16:58:50 -0700220 elif k == 'protmode':
221 pass # TODO(sleffler) need hostapd support
Nebojsa Sabovic36c10e92010-04-28 12:37:20 -0700222 elif k == 'ht':
223 htcaps.add('') # NB: ensure 802.11n setup below
224 elif k == 'htprotmode':
225 pass # TODO(sleffler) need hostapd support
226 elif k == 'rifs':
227 pass # TODO(sleffler) need hostapd support
228 elif k == 'wepmode':
229 pass # NB: meaningless for hostapd; ignore
Nebojsa Sabovicbc245c62010-04-28 16:58:50 -0700230 elif k == '-ampdu':
231 pass # TODO(sleffler) need hostapd support
Sam Leffler6969d1d2010-03-15 16:07:11 -0700232 else:
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700233 conf[k] = v
Sam Leffler6969d1d2010-03-15 16:07:11 -0700234
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700235 # Aggregate ht_capab.
236 if htcaps:
237 conf['ieee80211n'] = 1
238 conf['ht_capab'] = ''.join(htcaps)
Sam Leffler6969d1d2010-03-15 16:07:11 -0700239
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700240 # Generate hostapd.conf.
Nebojsa Sabovic138ff912010-04-06 15:47:42 -0700241 self.router.run("cat <<EOF >%s\n%s\nEOF\n" %
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700242 (self.hostapd['file'], '\n'.join(
243 "%s=%s" % kv for kv in conf.iteritems())))
244
245 # Run hostapd.
Nebojsa Sabovic138ff912010-04-06 15:47:42 -0700246 self.router.run("%s -B %s" %
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700247 (self.cmd_hostapd, self.hostapd['file']))
248
249 # Set up the bridge.
250 self.router.run("%s setfd %s %d" %
251 (self.cmd_brctl, self.bridgeif, 0))
252 self.router.run("%s addif %s %s" %
253 (self.cmd_brctl, self.bridgeif, self.wiredif))
254 self.router.run("%s link set %s up" %
255 (self.cmd_ip, self.wiredif))
256 self.router.run("%s link set %s up" %
257 (self.cmd_ip, self.bridgeif))
Nebojsa Sabovic138ff912010-04-06 15:47:42 -0700258
Sam Leffler6969d1d2010-03-15 16:07:11 -0700259# else:
260# # use iw to manually configure interface
261
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700262 self.hostapd['configured'] = True
Sam Leffler6969d1d2010-03-15 16:07:11 -0700263
264
265 def deconfig(self, params):
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700266 """ De-configure the AP (will also bring wlan and the bridge down) """
Sam Leffler6969d1d2010-03-15 16:07:11 -0700267
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700268 if not self.hostapd['configured']:
269 return
Sam Leffler6969d1d2010-03-15 16:07:11 -0700270
Nebojsa Sabovic4cc2ce92010-04-21 15:08:01 -0700271 # Taking down hostapd takes wlan0 and mon.wlan0 down.
272 self.router.run("pkill hostapd >/dev/null 2>&1", ignore_status=True)
273# self.router.run("rm -f %s" % self.hostapd['file'])
274
275 # Tear down the bridge.
276 self.router.run("%s link set %s down" % (self.cmd_ip, self.bridgeif),
277 ignore_status=True)
278 self.router.run("%s delbr %s" % (self.cmd_brctl, self.bridgeif),
279 ignore_status=True)
280
281 self.hostapd['configured'] = False