Merge "mmap: add mread command"
diff --git a/cmds/cpulog.c b/cmds/cpulog.c
index ff8498a..f58b17b 100644
--- a/cmds/cpulog.c
+++ b/cmds/cpulog.c
@@ -229,6 +229,8 @@
if (optind < argc)
usage_and_die(argv[0]);
+ setlinebuf(stdout);
+
ticks_per_sec = sysconf(_SC_CLK_TCK);
sleep(warmup_seconds);
diff --git a/cmds/wifi_files.c b/cmds/wifi_files.c
index b25e573..1d95683 100644
--- a/cmds/wifi_files.c
+++ b/cmds/wifi_files.c
@@ -609,6 +609,8 @@
char buf[24];
if (fgets(buf, sizeof(buf), fptr) != NULL)
fprintf(wifi_show_handle, " \"AutoType\": \"%s\"\n", buf);
+ fclose(fptr);
+ fptr = NULL;
}
fprintf(wifi_show_handle, "}\n");
diff --git a/cmds/wvtest/wvtest.sh b/cmds/wvtest/wvtest.sh
index 47b4366..19e0167 100644
--- a/cmds/wvtest/wvtest.sh
+++ b/cmds/wvtest/wvtest.sh
@@ -97,9 +97,9 @@
_wvfind_caller
_wvcheck $(_wvgetrv [ "$#" -eq 2 ]) "exactly 2 arguments"
echo "Comparing:" >&2
- echo "$1" >&2
+ echo "$1" | sed -e 's/^/<<< /' >&2
echo "--" >&2
- echo "$2" >&2
+ echo "$2" | sed -e 's/^/>>> /' >&2
_wvcheck $(_wvgetrv [ "$1" = "$2" ]) "'$1' = '$2'"
}
@@ -109,9 +109,9 @@
_wvfind_caller
_wvcheck $(_wvgetrv [ "$#" -eq 2 ]) "exactly 2 arguments"
echo "Comparing:" >&2
- echo "$1" >&2
+ echo "$1" | sed -e 's/^/<<< /' >&2
echo "--" >&2
- echo "$2" >&2
+ echo "$2" | sed -e 's/^/>>> /' >&2
_wvcheck $(_wvgetrv [ "$1" != "$2" ]) "'$1' != '$2'"
}
diff --git a/waveguide/waveguide.py b/waveguide/waveguide.py
index 36380bd..982bf23 100755
--- a/waveguide/waveguide.py
+++ b/waveguide/waveguide.py
@@ -51,6 +51,7 @@
waveguide [options...]
--
high-power This high-powered AP takes priority over low-powered ones
+tv-box The AP is a TV Box; other TV Boxes should avoid it
fake= Create a fake instance with the given MAC address
initial-scans= Number of immediate full channel scans at startup [1]
scan-interval= Seconds between full channel scan cycles (0 to disable) [0]
@@ -197,7 +198,7 @@
class WlanManager(object):
"""A class representing one wifi interface on the local host."""
- def __init__(self, phyname, vdevname, high_power):
+ def __init__(self, phyname, vdevname, high_power, tv_box):
self.phyname = phyname
self.vdevname = vdevname
self.mac = '\0\0\0\0\0\0'
@@ -206,6 +207,8 @@
self.allowed_freqs = set()
if high_power:
self.flags |= wgdata.ApFlags.HighPower
+ if tv_box:
+ self.flags |= wgdata.ApFlags.TvBox
self.bss_list = {}
self.channel_survey_list = {}
self.assoc_list = {}
@@ -383,13 +386,13 @@
for b in peer_data[peer_mac_addr]:
peer_ap = helpers.DecodeMAC(b.mac)
txt = ('peer:%s|bssid:%s|freq:%d|cap:0x%x|phy:%d|reg:%s|rssi:%s'
- '|last_seen:%d')
+ '|last_seen:%d|flags:0x%x')
if all(c in string.printable for c in b.reg):
reg = b.reg
else:
reg = ''
s = txt % (peer_mac_addr, peer_ap, b.freq, b.cap, b.phy, reg, b.rssi,
- b.last_seen)
+ b.last_seen, b.flags)
peer_ap_list.append(s)
content = '\n'.join(peer_ap_list)
if PEER_AP_LIST_FILE[0]:
@@ -808,7 +811,7 @@
return False
-def CreateManagers(managers, high_power):
+def CreateManagers(managers, high_power, tv_box):
"""Create WlanManager() objects, one per wifi interface."""
def ParseDevList(errcode, stdout, stderr):
@@ -855,7 +858,8 @@
for phy, dev in phy_devs.iteritems():
if dev not in existing_devs:
log.Debug('Creating wlan manager for (%r, %r)', phy, dev)
- managers.append(WlanManager(phy, dev, high_power=high_power))
+ managers.append(WlanManager(phy, dev, high_power=high_power,
+ tv_box=tv_box))
RunProc(callback=ParseDevList, args=['iw', 'dev'])
@@ -1055,12 +1059,13 @@
# them.
wlm = WlanManager(phyname='phy-%s' % fakemac[12:],
vdevname='wlan-%s' % fakemac[12:],
- high_power=opt.high_power)
+ high_power=opt.high_power,
+ tv_box=opt.tv_box)
wlm.mac = helpers.EncodeMAC(fakemac)
managers.append(wlm)
else:
# The list of managers is also refreshed occasionally in the main loop
- CreateManagers(managers, high_power=opt.high_power)
+ CreateManagers(managers, high_power=opt.high_power, tv_box=opt.tv_box)
if not managers:
raise Exception('no wifi AP-mode devices found. Try --fake.')
@@ -1118,7 +1123,7 @@
if ((opt.tx_interval and now - last_sent > opt.tx_interval) or (
opt.autochan_interval and now - last_autochan > opt.autochan_interval)):
if not opt.fake:
- CreateManagers(managers, high_power=opt.high_power)
+ CreateManagers(managers, high_power=opt.high_power, tv_box=opt.tv_box)
for m in managers:
m.UpdateStationInfo()
if opt.tx_interval and now - last_sent > opt.tx_interval:
@@ -1150,10 +1155,17 @@
for m, p in peers.values():
seen_bss_peers = [bss for bss in p.seen_bss if bss.mac in peers]
if p.me.mac in selfmacs: continue
- seen_peers[helpers.DecodeMAC(p.me.mac)] = seen_bss_peers
- for b in seen_bss_peers:
+ for i, b in enumerate(seen_bss_peers):
+ # `iw scan` can't see flags set in Waveguide.
+ # Join flags set in Waveguide with the results of the `iw scan`.
+ _, waveguide_peer = peers.get(b.mac)
+ if waveguide_peer:
+ # pylint:disable=protected-access
+ seen_bss_peers[i] = b._replace(flags=waveguide_peer.me.flags)
if b.mac in selfmacs:
bss_signal[helpers.DecodeMAC(p.me.mac)] = b.rssi
+
+ seen_peers[helpers.DecodeMAC(p.me.mac)] = seen_bss_peers
self_signals[m.mac] = bss_signal
peer_data[m.mac] = seen_peers
log.Log('%s: APs=%-4d peer-APs=%s stations=%s',
diff --git a/waveguide/wgdata.py b/waveguide/wgdata.py
index 3b84839..044c8ad 100644
--- a/waveguide/wgdata.py
+++ b/waveguide/wgdata.py
@@ -35,6 +35,7 @@
Can5G = 0x02 # device supports 5 GHz band
Can_Mask = 0x0f # mask of all bits referring to band capability
HighPower = 0x10 # high-power device takes precedence over low-power
+ TvBox = 0x20 # tv boxes shouldn't connect to tv boxes (yet)
PRE_FMT = '!4sB'
diff --git a/waveguide/wifiblaster_controller_test.py b/waveguide/wifiblaster_controller_test.py
index 9279b78..18b6564 100755
--- a/waveguide/wifiblaster_controller_test.py
+++ b/waveguide/wifiblaster_controller_test.py
@@ -15,6 +15,7 @@
"""Tests for WifiblasterController."""
+import glob
import os
import shutil
import sys
@@ -103,7 +104,6 @@
waveguide.WIFIBLASTER_DIR = tempfile.mkdtemp()
oldpath = os.environ['PATH']
oldtime = time.time
- faketime = [-1]
def FakeTime():
faketime[0] += 1
@@ -115,106 +115,114 @@
sys.path.insert(0, 'fake')
waveguide.opt = Empty()
waveguide.opt.status_dir = d
- manager = waveguide.WlanManager(phyname='phy-22:22', vdevname='wlan-22:22',
- high_power=True)
- manager.UpdateStationInfo()
- wc = waveguide.WifiblasterController([manager], d)
- def WriteConfig(k, v):
- open(os.path.join(d, 'wifiblaster.%s' % k), 'w').write(v)
+ for flags in [{'phyname': 'phy-22:22', 'vdevname': 'wlan-22:22',
+ 'high_power': True, 'tv_box': False},
+ {'phyname': 'phy-22:22', 'vdevname': 'wlan-22:22',
+ 'high_power': False, 'tv_box': True}]:
+ # Reset time and config directory before every test run.
+ faketime = [-1]
+ for f in glob.glob(os.path.join(d, '*')):
+ os.remove(f)
- WriteConfig('duration', '.1')
- WriteConfig('enable', 'False')
- WriteConfig('fraction', '10')
- WriteConfig('interval', '10')
- WriteConfig('rapidpolling', '10')
- WriteConfig('size', '1470')
+ manager = waveguide.WlanManager(**flags)
+ manager.UpdateStationInfo()
+ wc = waveguide.WifiblasterController([manager], d)
- # Disabled. No packet blasts should be run.
- print manager.GetState()
- for t in xrange(0, 100):
- wc.Poll(t)
+ def WriteConfig(k, v):
+ open(os.path.join(d, 'wifiblaster.%s' % k), 'w').write(v)
- def CountRuns():
- try:
- v = open('fake/wifiblaster.out').readlines()
- except IOError:
- return 0
- else:
- os.unlink('fake/wifiblaster.out')
- return len(v)
+ WriteConfig('duration', '.1')
+ WriteConfig('enable', 'False')
+ WriteConfig('fraction', '10')
+ WriteConfig('interval', '10')
+ WriteConfig('rapidpolling', '10')
+ WriteConfig('size', '1470')
- CountRuns() # get rid of any leftovers
- wvtest.WVPASSEQ(CountRuns(), 0)
+ # Disabled. No packet blasts should be run.
+ print manager.GetState()
+ for t in xrange(0, 100):
+ wc.Poll(t)
- # The first packet blast should be one
- # cycle later than the start time. This is not an implementation detail:
- # it prevents multiple APs from running simultaneous packet blasts if
- # packet blasts are enabled at the same time.
- WriteConfig('enable', 'True')
- wc.Poll(100)
- wvtest.WVPASSGE(wc.NextBlast(), 100)
- for t in xrange(101, 200):
- wc.Poll(t)
- wvtest.WVPASSGE(CountRuns(), 1)
+ def CountRuns():
+ try:
+ v = open('fake/wifiblaster.out').readlines()
+ except IOError:
+ return 0
+ else:
+ os.unlink('fake/wifiblaster.out')
+ return len(v)
- # Invalid parameter.
- # Disabled. No packet blasts should be run.
- WriteConfig('duration', '-1')
- for t in xrange(200, 300):
- wc.Poll(t)
- wvtest.WVPASSEQ(CountRuns(), 0)
+ CountRuns() # get rid of any leftovers
+ wvtest.WVPASSEQ(CountRuns(), 0)
- # Fix invalid parameter.
- # Enabled again with 10 second average interval.
- WriteConfig('duration', '.1')
- for t in xrange(300, 400):
- wc.Poll(t)
- wvtest.WVPASSGE(CountRuns(), 1)
+ # The first packet blast should be one
+ # cycle later than the start time. This is not an implementation detail:
+ # it prevents multiple APs from running simultaneous packet blasts if
+ # packet blasts are enabled at the same time.
+ WriteConfig('enable', 'True')
+ wc.Poll(100)
+ wvtest.WVPASSGE(wc.NextBlast(), 100)
+ for t in xrange(101, 200):
+ wc.Poll(t)
+ wvtest.WVPASSGE(CountRuns(), 1)
- # Run the packet blast at t=400 to restart the timer.
- wc.Poll(400)
- wvtest.WVPASSGE(CountRuns(), 0)
+ # Invalid parameter.
+ # Disabled. No packet blasts should be run.
+ WriteConfig('duration', '-1')
+ for t in xrange(200, 300):
+ wc.Poll(t)
+ wvtest.WVPASSEQ(CountRuns(), 0)
- # Next poll should be in at most one second regardless of interval.
- wvtest.WVPASSLE(wc.NextTimeout(), 401)
+ # Fix invalid parameter.
+ # Enabled again with 10 second average interval.
+ WriteConfig('duration', '.1')
+ for t in xrange(300, 400):
+ wc.Poll(t)
+ wvtest.WVPASSGE(CountRuns(), 1)
- # Enabled with longer average interval. The change in interval should
- # trigger a change in next poll timeout.
- WriteConfig('interval', '0.5')
- old_to = wc.NextBlast()
- wc.Poll(401)
- wvtest.WVPASSNE(old_to, wc.NextBlast())
- for t in xrange(402, 410):
- wc.Poll(t)
- wvtest.WVPASSGE(CountRuns(), 1)
+ # Run the packet blast at t=400 to restart the timer.
+ wc.Poll(400)
+ wvtest.WVPASSGE(CountRuns(), 0)
- # Switch back to a longer poll interval.
- WriteConfig('interval', '36000')
- ok = False
- for t in xrange(410, 600):
- wc.Poll(t)
- if wc.NextBlast() > t + 200:
- ok = True
- wvtest.WVPASS(ok)
+ # Next poll should be in at most one second regardless of interval.
+ wvtest.WVPASSLE(wc.NextTimeout(), 401)
- # And then try rapid polling for a limited time
- WriteConfig('rapidpolling', '800')
- ok = False
- for t in xrange(600, 700):
- wc.Poll(t)
- if wc.NextBlast() < t + 20:
- ok = True
- wvtest.WVPASS(ok)
+ # Enabled with longer average interval. The change in interval should
+ # trigger a change in next poll timeout.
+ WriteConfig('interval', '0.5')
+ old_to = wc.NextBlast()
+ wc.Poll(401)
+ wvtest.WVPASSNE(old_to, wc.NextBlast())
+ for t in xrange(402, 410):
+ wc.Poll(t)
+ wvtest.WVPASSGE(CountRuns(), 1)
- # Make sure rapid polling auto-disables
- ok = False
- for t in xrange(700, 900):
- wc.Poll(t)
- if wc.NextBlast() > t + 200:
- ok = True
- wvtest.WVPASS(ok)
+ # Switch back to a longer poll interval.
+ WriteConfig('interval', '36000')
+ ok = False
+ for t in xrange(410, 600):
+ wc.Poll(t)
+ if wc.NextBlast() > t + 200:
+ ok = True
+ wvtest.WVPASS(ok)
+ # And then try rapid polling for a limited time
+ WriteConfig('rapidpolling', '800')
+ ok = False
+ for t in xrange(600, 700):
+ wc.Poll(t)
+ if wc.NextBlast() < t + 20:
+ ok = True
+ wvtest.WVPASS(ok)
+
+ # Make sure rapid polling auto-disables
+ ok = False
+ for t in xrange(700, 900):
+ wc.Poll(t)
+ if wc.NextBlast() > t + 200:
+ ok = True
+ wvtest.WVPASS(ok)
finally:
time.time = oldtime
shutil.rmtree(d)
diff --git a/wifi/configs.py b/wifi/configs.py
index f78b368..d784858 100644
--- a/wifi/configs.py
+++ b/wifi/configs.py
@@ -306,11 +306,25 @@
return '\n'.join(hostapd_conf_parts)
-def generate_wpa_supplicant_config(ssid, passphrase):
- return '\n'.join(
- ('ctrl_interface=/var/run/wpa_supplicant',
- 'ap_scan=1',
- 'autoscan=exponential:1:30',
- subprocess.check_output(('wpa_passphrase',
- utils.sanitize_ssid(ssid),
- utils.validate_and_sanitize_psk(passphrase)))))
+def generate_wpa_supplicant_config(ssid, passphrase, opt):
+ """Generate a wpa_supplicant config from the provided arguments."""
+
+ network_block = subprocess.check_output(
+ ('wpa_passphrase',
+ utils.sanitize_ssid(ssid),
+ utils.validate_and_sanitize_psk(passphrase)))
+
+ if opt.bssid:
+ network_block_lines = network_block.splitlines(True)
+ network_block_lines[-1:-1] = ['\tbssid=%s\n' %
+ utils.validate_and_sanitize_bssid(opt.bssid)]
+ network_block = ''.join(network_block_lines)
+
+ lines = [
+ 'ctrl_interface=/var/run/wpa_supplicant',
+ 'ap_scan=1',
+ 'autoscan=exponential:1:30',
+ network_block
+ ]
+ return '\n'.join(lines)
+
diff --git a/wifi/configs_test.py b/wifi/configs_test.py
index 52ca4c9..a5c0c2e 100755
--- a/wifi/configs_test.py
+++ b/wifi/configs_test.py
@@ -20,6 +20,17 @@
}
"""
+_WPA_SUPPLICANT_CONFIG_BSSID = """ctrl_interface=/var/run/wpa_supplicant
+ap_scan=1
+autoscan=exponential:1:30
+network={
+\tssid="some ssid"
+\t#psk="some passphrase"
+\tpsk=41821f7ca3ea5d85beea7644ed7e0fefebd654177fa06c26fbdfdc3c599a317f
+\tbssid=12:34:56:78:90:ab
+}
+"""
+
@wvtest.wvtest
def generate_wpa_supplicant_config_test():
@@ -28,10 +39,21 @@
"Can't test generate_wpa_supplicant_config without wpa_passphrase.")
return
+ opt = FakeOptDict()
config = configs.generate_wpa_supplicant_config(
- 'some ssid', 'some passphrase')
+ 'some ssid', 'some passphrase', opt)
wvtest.WVPASSEQ(_WPA_SUPPLICANT_CONFIG, config)
+ opt.bssid = 'TotallyNotValid'
+ wvtest.WVEXCEPT(utils.BinWifiException,
+ configs.generate_wpa_supplicant_config,
+ 'some ssid', 'some passphrase', opt)
+
+ opt.bssid = '12:34:56:78:90:Ab'
+ config = configs.generate_wpa_supplicant_config(
+ 'some ssid', 'some passphrase', opt)
+ wvtest.WVPASSEQ(_WPA_SUPPLICANT_CONFIG_BSSID, config)
+
_PHY_INFO = """Wiphy phy0
max # scan SSIDs: 4
@@ -312,6 +334,7 @@
self.channel = 'auto'
self.autotype = 'NONDFS'
self.ssid = 'TEST_SSID'
+ self.bssid = ''
self.encryption = 'WPA2_PSK_AES'
self.force_restart = False
self.hidden_mode = False
diff --git a/wifi/utils.py b/wifi/utils.py
index fab7022..e665654 100644
--- a/wifi/utils.py
+++ b/wifi/utils.py
@@ -6,6 +6,7 @@
import collections
import os
+import re
import subprocess
import sys
import time
@@ -257,6 +258,16 @@
if unicodedata.category(c)[0] != 'C').encode('utf-8')
+def validate_and_sanitize_bssid(bssid):
+ maybe_octets = bssid.lower().split(':')
+ if (len(maybe_octets) == 6 and
+ all(re.match('[0-9a-f]{2}', maybe_octet)
+ for maybe_octet in maybe_octets)):
+ return ':'.join(maybe_octets)
+ else:
+ raise BinWifiException('%s is not a valid BSSID', bssid)
+
+
def validate_and_sanitize_psk(psk):
"""Validates a PSK and removes control characters.
diff --git a/wifi/wifi.py b/wifi/wifi.py
index 5ee618b..896f1ac 100755
--- a/wifi/wifi.py
+++ b/wifi/wifi.py
@@ -22,7 +22,7 @@
_OPTSPEC_FORMAT = """
{bin} set Enable or modify access points. Takes all options unless otherwise specified.
-{bin} setclient Enable or modify wifi clients. Takes -b, -P, -s, -S.
+{bin} setclient Enable or modify wifi clients. Takes -b, -P, -s, --bssid, -S.
{bin} stop|off Disable access points and clients. Takes -b, -P, -S.
{bin} stopap Disable access points. Takes -b, -P, -S.
{bin} stopclient Disable wifi clients. Takes -b, -P, -S.
@@ -33,6 +33,7 @@
c,channel= Channel to use [auto]
a,autotype= Autochannel method to use (LOW, HIGH, DFS, NONDFS, ANY,OVERLAP) [NONDFS]
s,ssid= SSID to use [{ssid}]
+bssid= BSSID to use []
e,encryption= Encryption type to use (WPA_PSK_AES, WPA2_PSK_AES, WPA12_PSK_AES, WPA_PSK_TKIP, WPA2_PSK_TKIP, WPA12_PSK_TKIP, WEP, or NONE) [WPA2_PSK_AES]
f,force-restart Force restart even if already running with these options
H,hidden-mode Enable hidden mode (disable SSID advertisements)
@@ -834,7 +835,7 @@
('ip', 'link', 'set', interface, 'address', mac_address))
wpa_config = configs.generate_wpa_supplicant_config(
- opt.ssid, os.environ['WIFI_CLIENT_PSK'])
+ opt.ssid, os.environ['WIFI_CLIENT_PSK'], opt)
if not _maybe_restart_wpa_supplicant(interface, wpa_config, opt):
return False