def set_client_wifi(opt): """Set up a wifi client in response to the 'setclient' command. Args: opt: The OptDict parsed from command line options. Returns: Whether wpa_supplicant successfully started and associated. Raises: BinWifiException: On various errors. """ if not opt.ssid: raise utils.BinWifiException('You must specify an ssid with --ssid') band = opt.band if band not in ('2.4', '5'): raise utils.BinWifiException('You must specify band with -b2.4 or -b5') psk = os.environ.get('WIFI_CLIENT_PSK', None) if band == '5' and quantenna.set_client_wifi(opt): return True mwifiex.set_recovery(experiment.enabled('MwifiexFirmwareRecovery')) phy = iw.find_phy(band, 'auto') if phy is None: utils.log("Couldn't find phy for band %s", band) return False interface = iw.find_interface_from_phy(phy, iw.INTERFACE_TYPE.client, opt.interface_suffix) if interface is None: # Create the client interface if it does not exist, using the same number as # an existing AP interface, which is stable across driver reloads. interface = client_interface_name(phy, opt.interface_suffix) if interface is None: raise utils.BinWifiException( 'AP interface not initialized for %s' % phy) if not iw.does_interface_exist(interface): utils.log('Creating client interface %s', interface) utils.subprocess_quiet(('iw', 'phy', phy, 'interface', 'add', interface, 'type', 'station'), no_stdout=True) ap_mac_address = utils.get_mac_address_for_interface( iw.find_interface_from_phy(phy, iw.INTERFACE_TYPE.ap, opt.interface_suffix)) mac_address = utils.increment_mac_address(ap_mac_address) subprocess.check_call( ('ip', 'link', 'set', interface, 'address', mac_address)) wpa_config = configs.generate_wpa_supplicant_config(opt.ssid, psk, opt) if not _set_wpa_supplicant_config(interface, wpa_config, opt): return False return True
def hostapd_options(band, ssid): """Returns hostapd options for bandsteering. Respects the experiments WifiBandsteering and WifiReverseBandsteering, in that order. Uses (and renames if necessary) a preexisting bandsteering directory for this band, if one exists. Otherwise, creates that directory. Args: band: The band on which hostapd is being started. ssid: The SSID of the AP. Returns: A list containing options to be passed to hostapd. Raises: BinWifiException: If the directory for storing bandsteering timestamps cannot be created. """ if experiment.enabled('WifiBandsteering'): target = '5' elif experiment.enabled('WifiReverseBandsteering'): target = '2.4' elif experiment.enabled('WifiHostapdLogging'): target = '' else: return [] band_dir = _bandsteering_dir(band, ssid) target_dir = _bandsteering_dir(target, ssid) # Make sure band_dir exist, since we want hostapd to write to it. If there's # a pre-existing one for the same band, use that; otherwise, create it. subdirs = (os.path.normpath(path) for path in glob.glob(os.path.join(_BANDSTEERING_DIR, '*/.'))) for subdir in subdirs: if os.path.basename(subdir).startswith(band): try: os.rename(subdir, band_dir) except OSError: raise utils.BinWifiException( "Couldn't update bandsteering directory") break else: try: os.makedirs(band_dir) except OSError as e: if e.errno != errno.EEXIST: raise utils.BinWifiException( "Couldn't create bandsteering directory %s", band_dir) result = ['-L', band_dir] if target and band != target: result += ['-S', target_dir] return result
def _wait_for_wpa_supplicant_to_associate(interface): """Wait for wpa_supplicant to associate. If it does not associate within a certain period of time, terminate it. Args: interface: The interface on which wpa_supplicant is running. Raises: BinWifiException: if wpa_supplicant fails to associate and also cannot be stopped to cleanup after the failure. Returns: Whether wpa_supplicant associated within the timeout. """ utils.log('Waiting for wpa_supplicant to connect') i = 0 for i in xrange(100): if _get_wpa_state(interface) == 'COMPLETED': utils.log('wpa_supplicant associated after %.1fs', i / 10.0) return True sys.stderr.write('.') sys.stderr.flush() time.sleep(0.1) utils.log('wpa_supplicant did not connect after %.1fs.', i / 10.0) if not _stop_wpa_supplicant(interface): raise utils.BinWifiException( "Couldn't stop wpa_supplicant after it failed to connect. " "Consider killing it manually.") return False
def scan_wifi(opt): """Prints 'iw scan' results. Args: opt: The OptDict parsed from command line options. Returns: True. Raises: BinWifiException: If an expected interface is not found. """ band = opt.band.split()[0] if band == '5' and quantenna.scan_wifi(opt): return True interface = iw.find_interface_from_band(band, iw.INTERFACE_TYPE.ap, opt.interface_suffix) if interface is None: raise utils.BinWifiException('No client interface for band %s', band) scan_args = [] if opt.scan_freq: scan_args += ['freq', str(opt.scan_freq)] if opt.scan_ap_force: scan_args += ['ap-force'] if opt.scan_passive: scan_args += ['passive'] print(iw.scan(interface, scan_args)) return True
def _ensure_initialized(mode): """Ensure that the device is in a state suitable for the given mode.""" if int(_qcsapi('is_startprod_done')): if (mode == 'scan' or mode == 'ap' and _qcsapi('get_mode', 'wifi0') == 'Access point' or mode == 'sta' and _qcsapi('get_mode', 'wifi0') == 'Station'): return _qcsapi('restore_default_config', 'noreboot', mode) _qcsapi('reload_in_mode', 'wifi0', mode) _qcsapi('rfenable', 1) else: _qcsapi('restore_default_config', 'noreboot', 'sta' if mode == 'scan' else mode) _, _, mac, _ = _get_interface('sta', '') if mac: _qcsapi('set_mac_addr', 'wifi0', mac) _qcsapi('startprod') for _ in xrange(30): if int(_qcsapi('is_startprod_done')): break time.sleep(1) else: raise utils.BinWifiException('startprod timed out') _qcsapi('rfenable', 1)
def scan_wifi(_): """Scan for APs.""" hif, _, _, _ = _get_interface('ap', '') if not hif: return False _ensure_initialized('scan') _qcsapi('start_scan', 'wifi0') for _ in xrange(30): if not int(_qcsapi('get_scanstatus', 'wifi0')): break time.sleep(1) else: raise utils.BinWifiException('scan timed out') for i in xrange(int(_qcsapi('get_results_ap_scan', 'wifi0'))): ssid, mac, channel, rssi, flags, protocols = _parse_scan_result( _qcsapi('get_properties_ap', 'wifi0', i)) print 'BSS %s(on %s)' % (mac, hif) print '\tfreq: %d' % (5000 + 5 * channel) print '\tsignal: %.2f' % rssi print '\tSSID: %s' % ssid if flags & 0x1: if protocols & 0x1: print '\tWPA:' if protocols & 0x2: print '\tRSN:' return True
def set_4address_mode(interface, on): try: setting = 'on' if on else 'off' subprocess.check_output( ['iw', 'dev', interface, 'set', '4addr', setting]) except subprocess.CalledProcessError as e: raise utils.BinWifiException('Failed to set 4addr mode %s: %s', setting, e)
def _maybe_restart_hostapd(interface, config, opt): """Starts or restarts hostapd unless doing so would be a no-op. The no-op case (i.e. hostapd is already running with an equivalent config) can be overridden with --force-restart. Args: interface: The interface on which to start hostapd. config: A hostapd configuration, as a string. opt: The OptDict parsed from command line options. Returns: Whether hostapd was started successfully. Raises: BinWifiException: On various errors. """ tmp_config_filename = utils.get_filename('hostapd', utils.FILENAME_KIND.config, interface, tmp=True) forced = False current_config = None try: with open(tmp_config_filename) as tmp_config_file: current_config = tmp_config_file.read() except IOError: pass if not _is_hostapd_running(interface): utils.log('hostapd not running yet, starting.') elif current_config != config: utils.log('hostapd config changed, restarting.') elif opt.force_restart: utils.log('Forced restart requested.') forced = True else: utils.log('hostapd-%s already configured and running', interface) return True if not _stop_hostapd(interface): raise utils.BinWifiException("Couldn't stop hostapd") # Set or unset 4-address mode. This has to be done while hostapd is down. utils.log('%s 4-address mode', 'Enabling' if opt.wds else 'Disabling') iw.set_4address_mode(interface, opt.wds) # We don't want to try to rewrite this file if this is just a forced restart. if not forced: utils.atomic_write(tmp_config_filename, config) if not _start_hostapd(interface, tmp_config_filename, opt.band, opt.ssid): utils.log( 'hostapd failed to start. Look at hostapd logs for details.') return False return True
def set_wifi(opt): """Enable AP.""" hif, lif, mac, vlan = _get_interface('ap', opt.interface_suffix) if not hif: return False if opt.encryption == 'WEP': raise utils.BinWifiException('WEP not supported') stop_ap_wifi(opt) try: _ensure_initialized('ap') _qcsapi('wifi_create_bss', lif, mac) _qcsapi('set_ssid', lif, opt.ssid) _qcsapi('set_bw', 'wifi0', opt.width) _qcsapi('set_channel', 'wifi0', 149 if opt.channel == 'auto' else opt.channel) if opt.encryption == 'NONE': _qcsapi('set_beacon_type', lif, 'Basic') else: protocol, authentication, encryption = opt.encryption.split('_') protocol = {'WPA': 'WPA', 'WPA2': '11i', 'WPA12': 'WPAand11i'}[protocol] authentication += 'Authentication' encryption += 'Encryption' _qcsapi('set_beacon_type', lif, protocol) _qcsapi('set_wpa_authentication_mode', lif, authentication) _qcsapi('set_wpa_encryption_modes', lif, encryption) _qcsapi('set_passphrase', lif, 0, os.environ['WIFI_PSK']) _qcsapi('set_option', lif, 'ssid_broadcast', int(not opt.hidden_mode)) _qcsapi('vlan_config', lif, 'enable') _qcsapi('vlan_config', lif, 'access', vlan) _qcsapi('vlan_config', 'pcie0', 'enable') _qcsapi('vlan_config', 'pcie0', 'trunk', vlan) _qcsapi('block_bss', lif, 0) _set_link_state(hif, 'up') _ifplugd_action(hif, 'up') except: stop_ap_wifi(opt) raise return True
def set_client_wifi(opt): """Enable client.""" hif, lif, _, vlan = _get_interface('sta', opt.interface_suffix) if not hif: return False stop_client_wifi(opt) try: _ensure_initialized('sta') _qcsapi('create_ssid', lif, opt.ssid) _qcsapi('set_bw', 'wifi0', 80) if opt.bssid: _qcsapi('set_ssid_bssid', lif, opt.ssid, opt.bssid) if opt.encryption == 'NONE' or not os.environ.get('WIFI_CLIENT_PSK'): _qcsapi('ssid_set_authentication_mode', lif, opt.ssid, 'NONE') else: _qcsapi('ssid_set_passphrase', lif, opt.ssid, 0, os.environ['WIFI_CLIENT_PSK']) _qcsapi('apply_security_config', lif) for _ in xrange(10): if _qcsapi('get_ssid', lif): break time.sleep(1) else: raise utils.BinWifiException('wpa_supplicant failed to connect') _qcsapi('vlan_config', lif, 'enable') _qcsapi('vlan_config', lif, 'access', vlan) _qcsapi('vlan_config', 'pcie0', 'enable') _qcsapi('vlan_config', 'pcie0', 'trunk', vlan) _set_link_state(hif, 'up') _ifplugd_action(hif, 'up') except: stop_client_wifi(opt) raise return True
def _restart_hostapd(interface, *overrides): """Restart hostapd from previous options. Only used by _set_wpa_supplicant_config, to restart hostapd after stopping it. Args: interface: The interface on which to restart hostapd. *overrides: A list of options to override the pre-existing ones. Returns: Whether hostapd was successfully restarted. Raises: BinWifiException: If reading previous settings fails. """ argv = persist.load_options('hostapd', interface, True) + list(overrides) if argv is None: raise utils.BinWifiException('Failed to read previous hostapd config') _run(argv)
def _set_wpa_supplicant_config(interface, config, opt): """Starts or restarts wpa_supplicant unless doing so would be a no-op. The no-op case (i.e. wpa_supplicant is already running with an equivalent config) can be overridden with --force-restart. Args: interface: The interface on which to start wpa_supplicant. config: A wpa_supplicant configuration, as a string. opt: The OptDict parsed from command line options. Returns: Whether wpa_supplicant was started successfully. Raises: BinWifiException: On various errors. """ tmp_config_filename = utils.get_filename('wpa_supplicant', utils.FILENAME_KIND.config, interface, tmp=True) forced = False current_config = None band = opt.band try: with open(tmp_config_filename) as tmp_config_file: current_config = tmp_config_file.read() except IOError: pass already_running = _is_wpa_supplicant_running(interface) if not already_running: utils.log('wpa_supplicant not running yet, starting.') elif current_config != config: # TODO(rofrankel): Consider using wpa_cli reconfigure here. utils.log('wpa_supplicant config changed, reconfiguring.') elif opt.force_restart: utils.log('Forced restart requested.') forced = True else: utils.log('wpa_supplicant-%s already configured and running', interface) return True if not forced: utils.atomic_write(tmp_config_filename, config) # TODO(rofrankel): Consider removing all the restart hostapd stuff when # b/30140131 is resolved. hostapd seems to keep working without being # restarted, at least on Camaro. restart_hostapd = False ap_interface = iw.find_interface_from_band(band, iw.INTERFACE_TYPE.ap, opt.interface_suffix) if _is_hostapd_running(ap_interface): restart_hostapd = True opt_without_persist = options.OptDict({}) opt_without_persist.persist = False opt_without_persist.band = opt.band opt_without_persist.interface_suffix = opt.interface_suffix if not stop_ap_wifi(opt_without_persist): raise utils.BinWifiException( "Couldn't stop hostapd to start wpa_supplicant.") if already_running: subprocess.check_call(['ifdown', interface]) subprocess.check_call( ['/etc/ifplugd/ifplugd.action', interface, 'down']) if not _reconfigure_wpa_supplicant(interface): raise utils.BinWifiException( 'Failed to reconfigure wpa_supplicant.') subprocess.check_call(['ifup', interface]) subprocess.check_call(['/etc/ifplugd/ifplugd.action', interface, 'up']) elif not _start_wpa_supplicant(interface, tmp_config_filename): raise utils.BinWifiException( 'wpa_supplicant failed to start. Look at wpa_supplicant logs for ' 'details.') if restart_hostapd: _restart_hostapd(ap_interface) return True
def set_wifi(opt): """Set up an access point in response to the 'set' command. Args: opt: The OptDict parsed from command line options. Returns: Whether setting up the AP succeeded. Raises: BinWifiException: On various errors. """ band = opt.band width = opt.width channel = opt.channel autotype = opt.autotype protocols = set(opt.protocols.split('/')) utils.validate_set_wifi_options(opt) psk = None if opt.encryption == 'WEP' or '_PSK_' in opt.encryption: psk = os.environ['WIFI_PSK'] if band == '5' and quantenna.set_wifi(opt): return True if iw.RUNNABLE_WL() and not iw.RUNNABLE_IW(): _set_wifi_broadcom(opt) return True if not iw.RUNNABLE_IW(): raise utils.BinWifiException("Can't proceed without iw") # If this phy is running client mode, we need to use its width/channel. phy = iw.find_phy(band, channel) if phy is None: raise utils.BinWifiException('no wifi phy for band=%s channel=%s', band, channel) # Check for calibration errors on ath10k. qca9880_cal.qca8990_calibration() mwifiex.set_recovery(experiment.enabled('MwifiexFirmwareRecovery')) client_interface = iw.find_interface_from_phy(phy, iw.INTERFACE_TYPE.client, opt.interface_suffix) if (client_interface is not None and _is_wpa_supplicant_running(client_interface)): # Wait up to ten seconds for interface width and channel to be available # (only relevant if wpa_supplicant was started recently). # TODO(rofrankel): Consider shortcutting this loop if wpa_cli shows status # is SCANNING (and other values)? utils.log( 'Client running on same band; finding its width and channel.') for _ in xrange(50): client_band = _get_wpa_band(client_interface) client_width, client_channel = iw.find_width_and_channel( client_interface) sys.stderr.write('.') sys.stderr.flush() if None not in (client_band, client_width, client_channel): band, width, channel = client_band, client_width, client_channel utils.log( 'Using band=%s, channel=%s, width=%s MHz from client', band, channel, width) break time.sleep(0.2) else: utils.log("Couldn't find band, width, and channel used by client " "(it may not be connected)") interface = iw.find_interface_from_phy(phy, iw.INTERFACE_TYPE.ap, opt.interface_suffix) if interface is None: raise utils.BinWifiException( 'no wifi interface found for band=%s channel=%s suffix=%s', band, channel, opt.interface_suffix) for ap_interface in iw.find_all_interfaces_from_phy( phy, iw.INTERFACE_TYPE.ap): if not _is_hostapd_running(ap_interface): continue if ap_interface == interface: continue # TODO(rofrankel): Figure out what to do about width. Unlike channel, # there's no 'auto' default; we don't know if 20 was requested or just # defaulted to. So it's not clear whether to override the other AP's # choice. _, other_ap_channel = iw.find_width_and_channel(ap_interface) if channel == 'auto': channel = other_ap_channel else: _restart_hostapd(ap_interface, '-c', channel) utils.log('interface: %s', interface) utils.log('Configuring cfg80211 wifi.') pid_filename = utils.get_filename('hostapd', utils.FILENAME_KIND.pid, interface, tmp=True) utils.log('pidfile: %s', pid_filename) autotype_filename = '/tmp/autotype.%s' % interface band_filename = '/tmp/band.%s' % interface width_filename = '/tmp/width.%s' % interface autochan_filename = '/tmp/autochan.%s' % interface old_autotype = utils.read_or_empty(autotype_filename) old_band = utils.read_or_empty(band_filename) old_width = utils.read_or_empty(width_filename) # Special case: if autochannel enabled and we've done it before, just use the # old autochannel. The main reason for this is we may not be able to run the # autochannel algorithm without stopping hostapd first, which defeats the code # that tries not to restart hostapd unnecessarily. if (channel == 'auto' and (autotype, band, width) == (old_autotype, old_band, old_width)): # ...but only if not forced mode. If it's forced, don't use the old # value, but don't wipe it either. if not opt.force_restart: autochan = utils.read_or_empty(autochan_filename) if autochan and int(autochan) > 0: utils.log('Reusing old autochannel=%s', autochan) channel = autochan else: # forget old autochannel setting if os.path.exists(autochan_filename): try: os.remove(autochan_filename) except OSError: utils.log('Failed to remove autochan file.') if channel == 'auto': utils.atomic_write(autochan_filename, '') try: channel = autochannel.scan(interface, band, autotype, width) except ValueError as e: raise utils.BinWifiException('Autochannel scan failed: %s', e) utils.atomic_write(autochan_filename, channel) utils.atomic_write(autotype_filename, autotype) utils.atomic_write(band_filename, band) utils.atomic_write(width_filename, width) utils.log('using channel=%s', channel) try: utils.log('getting phy info...') with open(os.devnull, 'w') as devnull: try: phy_info = subprocess.check_output(('iw', 'phy', phy, 'info'), stderr=devnull) except subprocess.CalledProcessError as e: raise utils.BinWifiException( 'Failed to get phy info for phy %s: %s', phy, e) hostapd_config = configs.generate_hostapd_config( phy_info, interface, band, channel, width, protocols, psk, opt) except ValueError as e: raise utils.BinWifiException('Invalid option: %s', e) return _maybe_restart_hostapd(interface, hostapd_config, opt)
def _set_wifi_broadcom(opt): """Set up wifi using wl, for Broadcom chips. Args: opt: The OptDict parsed from command line options. Raises: BinWifiException: On various errors. """ def wl(*args): utils.log('wl %s', ' '.join(args)) subprocess.check_call(('wl') + list(args)) utils.log('Configuring broadcom wifi.') wl('radio', 'on') wl('down') wl('ssid', '') band = opt.band if opt.channel != 'auto': band = 'auto' try: wl('band', {'2.4': 'b', '5': 'a', 'auto': 'auto'}[band]) except KeyError: raise utils.BinWifiException('Invalid band %s', band) wl('ap', '0') wl('up') if opt.channel == 'auto': # We can only run autochannel when ap=0, but setting ap=1 later will wipe # the value. So we have to capture the autochannel setting, then set it # later. 'wl autochannel 2' is thus useless. wl('autochannel', '1') # enough time to scan all the 2.4 or 5 GHz channels at 100ms each time.sleep(3) utils.log('wl autochannel') channel = subprocess.check_output(('wl', 'autochannel')).split()[0] wl('ap', '1') wl('chanspec', channel) wl('auth', '0') wl('infra', '1') try: wl('wsec', { '_AES': '4', 'TKIP': '2', 'WEP': '1', 'NONE': '0' }[opt.encryption[-4:]]) except KeyError: raise utils.BinWifiException('invalid crypto %s', opt.encryption) wl('sup_wpa', '1') try: wl('wpa_auth', { 'WPA_': '4', 'WPA2': '128', 'WEP': '0', 'NONE': '0' }[opt.encryption[:4]]) except KeyError: raise utils.BinWifiException('invalid crypto %s', opt.encryption) wl('up') if '_PSK_' in opt.encryption: # WPA keys must be added *before* setting the SSID wl('set_pmk', os.environ['WIFI_PSK']) wl('ssid', opt.ssid) elif opt.encryption == 'WEP': # WEP keys must be added *after* setting the SSID wl('ssid', opt.ssid) wl('set_pmk', os.environ['WIFI_PSK']) elif opt.encryption == 'NONE': wl('ssid', opt.ssid) else: raise utils.BinWifiException('invalid crypto %s', opt.encryption)
def generate_hostapd_config(phy_info, interface, band, channel, width, protocols, psk, opt): """Generates a hostpad config from the given arguments. Args: phy_info: The result of running 'iw phy <phy> info' where <phy> is the phy on which hostapd will run. interface: The interface on which hostapd will run. band: The band on which hostapd will run. channel: The channel on which hostapd will run. width: The channel width with which hostapd will run. protocols: The supported 802.11 protocols, as a collection of single-character strings (e.g. ['a', 'g', 'n']) psk: The PSK to use for the AP. opt: The OptDict parsed from command line options. Returns: The generated hostapd config, as a string. Raises: ValueError: For certain invalid combinations of arguments. """ utils.log('generating configuration...') if band == '2.4': hostapd_band = 'g' if set(('n', 'g')) & protocols else 'b' else: hostapd_band = 'a' ampdu = '' enable_80211n = '' enable_80211ac = '' require_ht = '' require_vht = '' ht20 = '' ht40 = '' ht_rxstbc = '' vht_settings = '' guard_interval = ('[SHORT-GI-20][SHORT-GI-40]' if opt.short_guard_interval else '') vht_guard_interval = '[SHORT-GI-80]' if opt.short_guard_interval else '' if 'RX STBC 3-stream' in phy_info: ht_rxstbc = '[RX-STBC123]' if 'RX STBC 2-stream' in phy_info: ht_rxstbc = '[RX-STBC12]' if 'RX STBC 1-stream' in phy_info: ht_rxstbc = '[RX-STBC1]' if 'n' in protocols: enable_80211n = 'ieee80211n=1' ht20 = '[HT20]' if 'ac' in protocols: if width == '80': enable_80211ac = 'ieee80211ac=1' if 'Maximum RX AMPDU length 16383 bytes' in phy_info: ampdu = '[MAX-A-MPDU-LEN-EXP1]' if 'Maximum RX AMPDU length 32767 bytes' in phy_info: ampdu = '[MAX-A-MPDU-LEN-EXP2]' if 'Maximum RX AMPDU length 65535 bytes' in phy_info: ampdu = '[MAX-A-MPDU-LEN-EXP3]' if 'Maximum RX AMPDU length 131071 bytes' in phy_info: ampdu = '[MAX-A-MPDU-LEN-EXP4]' if 'Maximum RX AMPDU length 262143 bytes' in phy_info: ampdu = '[MAX-A-MPDU-LEN-EXP5]' if 'Maximum RX AMPDU length 524287 bytes' in phy_info: ampdu = '[MAX-A-MPDU-LEN-EXP6]' if 'Maximum RX AMPDU length 1048575 bytes' in phy_info: ampdu = '[MAX-A-MPDU-LEN-EXP7]' if not set(('a', 'b', 'ab', 'g')) & protocols: require_ht = 'require_ht=1' if not set(('a', 'b', 'ab', 'g', 'n')) & protocols: require_vht = 'require_vht=1' if opt.encryption.startswith('WPA_PSK_'): auth_algs, wpa = 1, 1 elif opt.encryption.startswith('WPA2_PSK_'): auth_algs, wpa = 1, 2 elif opt.encryption.startswith('WPA12_PSK_'): auth_algs, wpa = 1, 3 elif opt.encryption.startswith('WEP'): auth_algs, wpa = 3, 0 elif opt.encryption.startswith('NONE'): auth_algs, wpa = 1, 0 else: raise ValueError('Invalid crypto protocol: %s' % opt.encryption) if opt.encryption[-4:] in ('_AES', 'WEP', 'NONE'): wpa_pairwise = 'CCMP' elif opt.encryption.endswith('_TKIP'): wpa_pairwise = 'TKIP' else: raise ValueError('Invalid crypto protocol: %s' % opt.encryption) if int(width) >= 40: if '%s+' % channel in _HT_DIRECTIONS.split(): ht40 = '[HT40+]' elif '%s-' % channel in _HT_DIRECTIONS.split(): ht40 = '[HT40-]' else: raise ValueError( 'HT40 requested but not available on channel %s.' % channel) if width == '80': ldpc = '[RXLDPC]' vht_base = '' for base in _VHT_BASES.split(): if base.startswith('%s=' % channel): vht_base = base.split('=')[1] break if vht_base: vht_settings = _VHT_SETTINGS_TPL.format( ampdu=ampdu, vht_guard_interval=vht_guard_interval, ldpc=ldpc, vht_base=int(vht_base) + 6) else: raise ValueError( 'VHT80 requested but not available on channel %s' % channel) try: bssid = None if subprocess.call(('is-network-box')) == 0: mac_addr_hnvram = ('MAC_ADDR_WIFI' + ('' if interface.startswith('wlan0') else '2')) bssid = utils.subprocess_output_or_none( ('hnvram', '-qr', mac_addr_hnvram)) if bssid is None: bssid = utils.subprocess_output_or_none( ('hnvram', '-rq', 'MAC_ADDR')) if bssid is None: raise utils.BinWifiException( 'Box has no MAC_ADDR_WIFI, MAC_ADDR_WIFI2, or MAC_ADDR. You can ' 'set these with e.g. ' "'# hnvram -w MAC_ADDR_WIFI=00:00:00:00:00:00'") except OSError: pass enable_wmm = 'wmm_enabled=1' if opt.enable_wmm else '' hidden = 'ignore_broadcast_ssid=1' if opt.hidden_mode else '' bridge = 'bridge=%s' % opt.bridge if opt.bridge else '' ap_isolate = 'ap_isolate=1' if opt.client_isolation else '' wds = 'wds_sta=1' if opt.wds else '' hostapd_conf_parts = [ _HOSTCONF_TPL.format(interface=interface, band=band, channel=channel, width=width, protocols=protocols, hostapd_band=hostapd_band, enable_80211n=enable_80211n, enable_80211ac=enable_80211ac, require_ht=require_ht, require_vht=require_vht, ht20=ht20, ht40=ht40, ht_rxstbc=ht_rxstbc, vht_settings=vht_settings, guard_interval=guard_interval, enable_wmm=enable_wmm, hidden=hidden, ap_isolate=ap_isolate, auth_algs=auth_algs, bridge=bridge, ssid=utils.sanitize_ssid(opt.ssid), wds=wds, vendor_elements=get_vendor_elements(opt)) ] if opt.encryption != 'NONE': hostapd_conf_parts.append( _HOSTCONF_WPA_TPL.format(psk=utils.validate_and_sanitize_psk(psk), wpa=wpa, wpa_pairwise=wpa_pairwise)) if experiment.enabled('Wifi80211k'): hostapd_conf_parts.append( _EXPERIMENT_80211K_TPL.format(interface=interface)) if opt.yottasecond_timeouts: hostapd_conf_parts.append(_YOTTASECOND_TIMEOUTS_TPL) elif opt.extra_short_timeouts >= 2: hostapd_conf_parts.append(_EXTRA_SHORT_TIMEOUTS2_TPL) elif opt.extra_short_timeouts >= 1: hostapd_conf_parts.append(_EXTRA_SHORT_TIMEOUTS1_TPL) # Track the active experiments the last time hostapd was started: # - for easier examination of the state # - to make sure the config counts as changed whenever the set of # experiments changes. active_experiments = [i for i in EXPERIMENTS if experiment.enabled(i)] hostapd_conf_parts.append('# Experiments: (%s)\n' % ','.join(active_experiments)) utils.log('configuration ready.') return '\n'.join(hostapd_conf_parts)