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 | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 24 | # Command locations. |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 25 | 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 Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 30 | # Router host. |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 31 | self.router = host |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 32 | |
| 33 | # Network interfaces. |
Nebojsa Sabovic | 36c10e9 | 2010-04-28 12:37:20 -0700 | [diff] [blame] | 34 | self.bridgeif = params.get('bridgedev', "br-lan") |
| 35 | self.wiredif = params.get('wiredev', "eth1") |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 36 | self.wlanif = "wlan0" |
| 37 | |
| 38 | # Default to 1st available wireless phy. |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 39 | if "phydev" not in params: |
| 40 | output = self.router.run("%s list" % self.cmd_iw).stdout |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 41 | test = re.compile("Wiphy (.*)") |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 42 | for line in output.splitlines(): |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 43 | m = test.match(line) |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 44 | if m: |
| 45 | self.phydev = m.group(1) |
| 46 | break |
| 47 | else: |
Nebojsa Sabovic | bae8fd4 | 2010-04-23 13:47:23 -0700 | [diff] [blame] | 48 | raise error.TestFail("No Wireless NIC detected on the device") |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 49 | else: |
| 50 | self.phydev = params['phydev'] |
| 51 | |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 52 | |
| 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 Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 88 | |
Nebojsa Sabovic | bc245c6 | 2010-04-28 16:58:50 -0700 | [diff] [blame^] | 89 | # Place us in the US by default |
| 90 | self.router.run("%s reg set US" % self.cmd_iw) |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 91 | |
| 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 Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 100 | if params['type'] == "ap" or params['type'] == "hostap": |
| 101 | self.apmode = True |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 102 | phytype = { |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 103 | "sta" : "managed", |
| 104 | "monitor" : "monitor", |
| 105 | "adhoc" : "adhoc", |
| 106 | "ibss" : "ibss", |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 107 | "ap" : "managed", # NB: handled by hostapd |
| 108 | "hostap" : "managed", # NB: handled by hostapd |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 109 | "mesh" : "mesh", |
| 110 | "wds" : "wds", |
| 111 | }[params['type']] |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 112 | phydev = params.get('phydev', self.phydev) |
| 113 | self.router.run("%s phy %s interface add %s type %s" % |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 114 | (self.cmd_iw, phydev, self.wlanif, phytype)) |
| 115 | |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 116 | |
| 117 | |
| 118 | def destroy(self, params): |
| 119 | """ Destroy a previously created device """ |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 120 | # For linux, this is the same as deconfig. |
| 121 | self.deconfig(params) |
| 122 | |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 123 | |
| 124 | |
| 125 | def config(self, params): |
| 126 | """ Configure the AP per test requirements """ |
| 127 | |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 128 | if self.hostapd['configured']: |
| 129 | self.deconfig({}) |
| 130 | |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 131 | if self.apmode: |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 132 | # Construct the hostapd.conf file and start hostapd. |
| 133 | conf = self.hostapd['conf'] |
| 134 | htcaps = set() |
| 135 | |
Nebojsa Sabovic | bae8fd4 | 2010-04-23 13:47:23 -0700 | [diff] [blame] | 136 | conf['driver'] = params.get('hostapd_driver', |
| 137 | self.hostapd['driver']) |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 138 | |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 139 | for k, v in params.iteritems(): |
| 140 | if k == 'ssid': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 141 | conf['ssid'] = v |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 142 | elif k == 'channel': |
| 143 | freq = int(v) |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 144 | |
| 145 | # 2.4GHz |
| 146 | if freq < 2500: |
Nebojsa Sabovic | 36c10e9 | 2010-04-28 12:37:20 -0700 | [diff] [blame] | 147 | # Make sure hw_mode is set |
| 148 | if conf.get('hw_mode') == 'a': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 149 | 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 Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 158 | else: |
Nebojsa Sabovic | 36c10e9 | 2010-04-28 12:37:20 -0700 | [diff] [blame] | 159 | # Make sure hw_mode is set |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 160 | conf['hw_mode'] = 'a' |
| 161 | # Freq = 5 * chan + 4000 |
| 162 | if freq >= 4915 and freq <= 4980: |
Nebojsa Sabovic | bc245c6 | 2010-04-28 16:58:50 -0700 | [diff] [blame^] | 163 | conf['channel'] = (freq - 4000) / 5 |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 164 | # Freq = 5 * chan + 5000 |
| 165 | elif freq >= 5035 and freq <= 5825: |
| 166 | conf['channel'] = (freq - 5000) / 5 |
| 167 | |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 168 | elif k == 'country': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 169 | conf['country_code'] = v |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 170 | elif k == 'dotd': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 171 | conf['ieee80211d'] = 1 |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 172 | elif k == '-dotd': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 173 | conf['ieee80211d'] = 0 |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 174 | elif k == 'mode': |
| 175 | if v == '11a': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 176 | conf['hw_mode'] = 'a' |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 177 | elif v == '11g': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 178 | conf['hw_mode'] = 'g' |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 179 | elif v == '11b': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 180 | conf['hw_mode'] = 'b' |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 181 | elif v == '11n': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 182 | conf['ieee80211n'] = 1 |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 183 | elif k == 'bintval': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 184 | conf['beacon_int'] = v |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 185 | elif k == 'dtimperiod': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 186 | conf['dtim_period'] = v |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 187 | elif k == 'rtsthreshold': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 188 | conf['rts_threshold'] = v |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 189 | elif k == 'fragthreshold': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 190 | conf['fragm_threshold'] = v |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 191 | elif k == 'shortpreamble': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 192 | conf['preamble'] = 1 |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 193 | elif k == 'authmode': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 194 | if v == "open": |
| 195 | conf['auth_algs'] = 1 |
| 196 | elif v == "shared": |
| 197 | conf['auth_algs'] = 2 |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 198 | elif k == 'hidessid': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 199 | conf['ignore_broadcast_ssid'] = 1 |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 200 | elif k == 'wme': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 201 | conf['wmm_enabled'] = 1 |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 202 | elif k == '-wme': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 203 | conf['wmm_enabled'] = 0 |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 204 | elif k == 'deftxkey': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 205 | conf['wep_default_key'] = v |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 206 | elif k == 'ht20': |
Nebojsa Sabovic | 36c10e9 | 2010-04-28 12:37:20 -0700 | [diff] [blame] | 207 | htcaps.add('') # NB: ensure 802.11n setup below |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 208 | conf['wmm_enabled'] = 1 |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 209 | elif k == 'ht40': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 210 | htcaps.add('[HT40-]') |
| 211 | htcaps.add('[HT40+]') |
| 212 | conf['wmm_enabled'] = 1 |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 213 | elif k == 'shortgi': |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 214 | htcaps.add('[SHORT-GI-20]') |
| 215 | htcaps.add('[SHORT-GI-40]') |
Nebojsa Sabovic | 36c10e9 | 2010-04-28 12:37:20 -0700 | [diff] [blame] | 216 | elif k == 'pureg': |
| 217 | pass # TODO(sleffler) need hostapd support |
| 218 | elif k == 'puren': |
| 219 | pass # TODO(sleffler) need hostapd support |
Nebojsa Sabovic | bc245c6 | 2010-04-28 16:58:50 -0700 | [diff] [blame^] | 220 | elif k == 'protmode': |
| 221 | pass # TODO(sleffler) need hostapd support |
Nebojsa Sabovic | 36c10e9 | 2010-04-28 12:37:20 -0700 | [diff] [blame] | 222 | 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 Sabovic | bc245c6 | 2010-04-28 16:58:50 -0700 | [diff] [blame^] | 230 | elif k == '-ampdu': |
| 231 | pass # TODO(sleffler) need hostapd support |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 232 | else: |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 233 | conf[k] = v |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 234 | |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 235 | # Aggregate ht_capab. |
| 236 | if htcaps: |
| 237 | conf['ieee80211n'] = 1 |
| 238 | conf['ht_capab'] = ''.join(htcaps) |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 239 | |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 240 | # Generate hostapd.conf. |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 241 | self.router.run("cat <<EOF >%s\n%s\nEOF\n" % |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 242 | (self.hostapd['file'], '\n'.join( |
| 243 | "%s=%s" % kv for kv in conf.iteritems()))) |
| 244 | |
| 245 | # Run hostapd. |
Nebojsa Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 246 | self.router.run("%s -B %s" % |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 247 | (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 Sabovic | 138ff91 | 2010-04-06 15:47:42 -0700 | [diff] [blame] | 258 | |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 259 | # else: |
| 260 | # # use iw to manually configure interface |
| 261 | |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 262 | self.hostapd['configured'] = True |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 263 | |
| 264 | |
| 265 | def deconfig(self, params): |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 266 | """ De-configure the AP (will also bring wlan and the bridge down) """ |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 267 | |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 268 | if not self.hostapd['configured']: |
| 269 | return |
Sam Leffler | 6969d1d | 2010-03-15 16:07:11 -0700 | [diff] [blame] | 270 | |
Nebojsa Sabovic | 4cc2ce9 | 2010-04-21 15:08:01 -0700 | [diff] [blame] | 271 | # 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 |