Пример #1
0
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
Пример #2
0
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
Пример #3
0
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
Пример #4
0
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
Пример #5
0
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)
Пример #6
0
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
Пример #7
0
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)
Пример #8
0
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
Пример #9
0
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
Пример #10
0
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
Пример #11
0
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)
Пример #12
0
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
Пример #13
0
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)
Пример #14
0
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)
Пример #15
0
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)