Esempio n. 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
Esempio n. 2
0
def _reload_driver():
    """Reload the ath10k driver so it picks up modified calibration file."""
    ret = utils.subprocess_quiet(('rmmod', 'ath10k_pci'))
    if ret != 0:
        _log('rmmod ath10k_pci failed: {}.'.format(ret))
        return

    ret = utils.subprocess_quiet(('modprobe', 'ath10k_pci'))
    if ret != 0:
        _log('modprobe ath10k_pci failed: {}.'.format(ret))
        return

    _log('reload ath10k driver complete')
Esempio n. 3
0
def _stop_hostapd(interface):
    """Stops hostapd from running on the given interface.

  Also removes the pid file, sets them interface down and deletes the monitor
  interface, if it exists.

  Args:
    interface: The interface on which to stop hostapd.

  Returns:
    Whether hostapd was successfully stopped and cleaned up.
  """
    if not _is_hostapd_running(interface):
        utils.log('hostapd already not running.')
        return True

    config_filename = utils.get_filename('hostapd',
                                         utils.FILENAME_KIND.config,
                                         interface,
                                         tmp=True)
    pid_filename = utils.get_filename('hostapd',
                                      utils.FILENAME_KIND.pid,
                                      interface,
                                      tmp=True)
    if not utils.kill_pid('hostapd .* %s$' % config_filename, pid_filename):
        return False

    # TODO(apenwarr): hostapd doesn't always delete interface mon.$ifc.  Then it
    # gets confused by the fact that it already exists.  Let's help out.  We
    # should really fix this by eliminating the need for hostapd to have a
    # monitor interface at all (which is deprecated anyway) Remove this line when
    # our hostapd no longer needs a monitor interface.
    utils.subprocess_quiet(('iw', 'dev', 'mon.%s' % interface, 'del'))

    subprocess.check_call(('ip', 'link', 'set', interface, 'down'))

    return True
Esempio n. 4
0
def create_client_interface(interface, phy, suffix):
    """Creates a client interface.

  Args:
    interface: The name of the interface to create.
    phy: The phy on which to create the interface.
    suffix: The suffix of the AP interface on the same phy.

  Returns:
    Whether interface creation succeeded.
  """
    utils.log('Creating client interface %s.', interface)
    try:
        utils.subprocess_quiet(('iw', 'phy', phy, 'interface', 'add',
                                interface, 'type', 'station'),
                               no_stdout=True)

        ap_mac_address = utils.get_mac_address_for_interface(
            find_interface_from_phy(phy, INTERFACE_TYPE.ap, suffix))
        mac_address = utils.increment_mac_address(ap_mac_address)
        subprocess.check_call(
            ('ip', 'link', 'set', interface, 'address', mac_address))
    except subprocess.CalledProcessError as e:
        utils.log('Creating client interface failed: %s', e)
Esempio n. 5
0
def _wpa_cli(program, interface, command):
    return utils.subprocess_quiet((program, '-i', interface, command),
                                  no_stdout=True) == 0
Esempio n. 6
0
def _is_hostapd_running(interface):
    return utils.subprocess_quiet(('hostapd_cli', '-i', interface, 'quit'),
                                  no_stdout=True) == 0
Esempio n. 7
0
def does_interface_exist(interface):
    return utils.subprocess_quiet(('iw', interface, 'info'),
                                  no_stdout=True) == 0
Esempio n. 8
0
def scan(interface, band, autotype, width):
    """Do an autochannel scan and return the recommended channel.

  Args:
    interface: The interface on which to scan.
    band: The band on which to scan.
    autotype: Determines permitted frequencies.  See get_permitted_frequencies
      for valid values.
    width: Determines permitted frequencies.  See get_permitted_frequencies for
      valid values.

  Returns:
    The channel to use, or None if no recommendation can be made.
  """
    utils.log('Doing autochannel scan.')

    permitted_frequencies = get_permitted_frequencies(band, autotype, width)

    subprocess.call(('ip', 'link', 'set', interface, 'up'))

    # TODO(apenwarr): We really want to clear any old survey results first.  But
    # there seems to be no iw command for that yet...
    #
    # TODO(apenwarr): This only scans each channel for 100ms.  Ideally it should
    # scan for longer, to get a better activity sample.  It would also be nice to
    # continue scanning in the background while hostapd is running, using 'iw
    # offchannel'.  Retry this a few times if it fails, just in case there was a
    # scan already in progress started somewhere else (e.g. from waveguide).
    for _ in xrange(9):
        if utils.subprocess_quiet(('iw', 'dev', interface, 'scan', 'passive'),
                                  no_stdout=True) == 0:
            break
        time.sleep(0.5)

    # TODO(apenwarr): This algorithm doesn't deal with overlapping channels. Just
    # because channel 1 looks good doesn't mean we should use it; activity in
    # overlapping channels could destroy performance.  In fact, overlapping
    # channel activity is much worse than activity on the main channel.  Also, if
    # using 40 MHz or 80 MHz channel width, we should count activity in all the 20
    # MHz sub-channels separately, and choose the least-active sub-channel as the
    # primary.
    best_frequency = best_noise = best_ratio = frequency = None
    for tokens in utils.subprocess_line_tokens(
        ('iw', 'dev', interface, 'survey', 'dump')):
        # TODO(apenwarr): Randomize the order of channels.  Otherwise when channels
        # are all about equally good, we would always choose exactly the same
        # channel, which might be bad in the case of hidden nodes.
        if len(tokens) >= 2 and tokens[0] == 'frequency:':
            frequency = tokens[1]
            noise = active = busy = None
        elif len(tokens) >= 2 and tokens[0] == 'noise:':
            noise = int(tokens[1])
        elif len(tokens) >= 4 and tokens[:3] == ('channel', 'active', 'time:'):
            active = int(tokens[3])
        elif len(tokens) >= 4 and tokens[:3] == ('channel', 'receive',
                                                 'time:'):
            busy = int(tokens[3])
            # TODO(rofrankel): busy or 1 might make more sense than busy + 1 here;
            # need to discuss with apenwarr@.
            ratio = (active + 1) * 1000 / (busy + 1)

            if frequency not in permitted_frequencies.split():
                continue

            # Some radios support both bands, but we only want to match channels on
            # the band we have chosen.
            if band[0] != frequency[0]:
                continue

            utils.log('freq=%s ratio=%s noise=%s', frequency, ratio, noise)

            if best_noise is None or best_noise - 15 > noise or best_ratio < ratio:
                best_frequency, best_ratio, best_noise = frequency, ratio, noise

    if not best_frequency:
        utils.log('Autoscan did not find any channel, picking random channel.')
        utils.log('Permitted frequencies: %s', permitted_frequencies)
        if not permitted_frequencies:
            utils.log('No default channel: type=%s band=%s width=%s', autotype,
                      band, width)
            return None
        best_frequency = random.choice(permitted_frequencies.split())

    utils.log('autofreq=%s', best_frequency)

    for tokens in utils.subprocess_line_tokens(('iw', 'phy')):
        if len(tokens) >= 4 and tokens[2] == 'MHz':
            frequency = tokens[1]
            if frequency == best_frequency:
                channel = tokens[3].strip('[]')
                break

    if not channel:
        utils.log('No channel number matched freq=%s.', best_frequency)
        return None

    utils.log('autochannel=%s', channel)

    return channel