Merge "ginstall: Output progress to /tmp/ginstall/progress."
diff --git a/cmds/Makefile b/cmds/Makefile
index 4778036..45580b2 100644
--- a/cmds/Makefile
+++ b/cmds/Makefile
@@ -33,6 +33,7 @@
dnsck \
freemegs \
gfhd254_reboot \
+ gflldpd \
gstatic \
http_bouncer \
ionice \
@@ -52,6 +53,7 @@
LIB_TARGETS=\
stdoutline.so
HOST_TEST_TARGETS=\
+ host-gflldpd_test \
host-netusage_test \
host-utils_test \
host-isoping_test
@@ -272,6 +274,10 @@
anonid: anonid.o
host-anonid: host-anonid.o
anonid host-anonid: LIBS += -lcrypto
+host-gflldpd_test.o: CXXFLAGS += -D WVTEST_CONFIGURED -I ../wvtest/cpp
+host-gflldpd_test.o: gflldpd.c
+host-gflldpd_test: LIBS+=$(HOST_LIBS) -lm -lstdc++
+host-gflldpd_test: host-gflldpd_test.o host-wvtestmain.o host-wvtest.o
TESTS = $(wildcard test-*.sh) $(wildcard test-*.py) $(wildcard *_test.py) $(TEST_TARGETS)
diff --git a/cmds/gflldpd.c b/cmds/gflldpd.c
new file mode 100644
index 0000000..44c2dd2
--- /dev/null
+++ b/cmds/gflldpd.c
@@ -0,0 +1,246 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013 Keichi Takahashi keichi.t@me.com
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* Substantially derived from * https://github.com/keichi/tiny-lldpd
+ * also under the MIT license */
+
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <netinet/if_ether.h>
+#include <netinet/in.h>
+#include <netpacket/packet.h>
+#include <sys/socket.h>
+
+#define MAXINTERFACES 8
+const char *ifnames[MAXINTERFACES] = {0};
+int ninterfaces = 0;
+
+uint8_t sendbuf[1024];
+
+const uint8_t lldpaddr[ETH_ALEN] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e};
+#define ETH_P_LLDP 0x88cc
+#define TLV_END 0
+#define TLV_CHASSIS_ID 1
+#define TLV_PORT_ID 2
+#define TLV_TTL 3
+#define TLV_PORT_DESCRIPTION 4
+#define TLV_SYSTEM_NAME 5
+
+#define CHASSIS_ID_MAC_ADDRESS 4
+#define PORT_ID_MAC_ADDRESS 3
+
+static int write_lldp_tlv_header(void *p, int type, int length)
+{
+ *((uint16_t *)p) = htons((type & 0x7f) << 9 | (length & 0x1ff));
+ return 2;
+}
+
+
+static int write_lldp_type_subtype_tlv(size_t offset,
+ uint8_t type, uint8_t subtype, int length, const void *data)
+{
+ uint8_t *p = sendbuf + offset;
+
+ if ((offset + 2 + 1 + length) > sizeof(sendbuf)) {
+ fprintf(stderr, "LLDP frame too large %zd > %zd\n",
+ (offset + 2 + 1 + length), sizeof(sendbuf));
+ exit(1);
+ }
+
+ p += write_lldp_tlv_header(p, type, length + 1);
+ *p++ = subtype;
+ memcpy(p, data, length);
+ p += length;
+
+ return (p - sendbuf);
+}
+
+
+static int write_lldp_type_tlv(size_t offset, uint8_t type,
+ int length, const void *data)
+{
+ uint8_t *p = sendbuf + offset;
+
+ if ((offset + 2 + length) > sizeof(sendbuf)) {
+ fprintf(stderr, "LLDP frame too large %zd > %zd\n",
+ (offset + 2 + length), sizeof(sendbuf));
+ exit(1);
+ }
+
+ p += write_lldp_tlv_header(p, type, length);
+ memcpy(p, data, length);
+ p += length;
+
+ return (p - sendbuf);
+}
+
+
+static int write_lldp_end_tlv(size_t offset)
+{
+ uint8_t *p = sendbuf + offset;
+
+ if ((offset + 2) > sizeof(sendbuf)) {
+ fprintf(stderr, "LLDP frame too large %zd > %zd\n",
+ (offset + 2), sizeof(sendbuf));
+ exit(1);
+ }
+
+ offset += write_lldp_tlv_header(p, TLV_END, 0);
+ return offset;
+}
+
+
+static void mac_str_to_bytes(const char *macstr, uint8_t *mac)
+{
+ if (sscanf(macstr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+ &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]) != 6) {
+ fprintf(stderr, "Invalid MAC address: %s\n", macstr);
+ exit(1);
+ }
+}
+
+
+static size_t format_lldp_packet(const char *macaddr, const char *ifname,
+ const char *serial)
+{
+ uint8_t saddr[ETH_ALEN];
+ size_t offset = 0;
+ struct ether_header *eh = (struct ether_header *)sendbuf;
+ uint16_t ttl;
+
+ mac_str_to_bytes(macaddr, saddr);
+ memset(sendbuf, 0, sizeof(sendbuf));
+
+ eh = (struct ether_header *)sendbuf;
+ memcpy(eh->ether_shost, saddr, sizeof(eh->ether_shost));
+ memcpy(eh->ether_dhost, lldpaddr, sizeof(eh->ether_dhost));
+ eh->ether_type = htons(ETH_P_LLDP);
+ offset = sizeof(*eh);
+
+ offset = write_lldp_type_subtype_tlv(offset,
+ TLV_CHASSIS_ID, CHASSIS_ID_MAC_ADDRESS, ETH_ALEN, saddr);
+ offset = write_lldp_type_subtype_tlv(offset,
+ TLV_PORT_ID, PORT_ID_MAC_ADDRESS, ETH_ALEN, saddr);
+
+ ttl = htons(120);
+ offset = write_lldp_type_tlv(offset, TLV_TTL, sizeof(ttl), &ttl);
+
+ offset = write_lldp_type_tlv(offset,
+ TLV_PORT_DESCRIPTION, strlen(ifname), ifname);
+ offset = write_lldp_type_tlv(offset,
+ TLV_SYSTEM_NAME, strlen(serial), serial);
+ offset = write_lldp_end_tlv(offset);
+
+ return offset;
+}
+
+
+#ifndef UNIT_TESTS
+static void send_lldp_packet(int s, size_t len, const char *ifname)
+{
+ struct sockaddr_ll sll;
+
+ memset(&sll, 0, sizeof(sll));
+ sll.sll_family = PF_PACKET;
+ sll.sll_ifindex = if_nametoindex(ifname);
+ sll.sll_hatype = ARPHRD_ETHER;
+ sll.sll_halen = ETH_ALEN;
+ sll.sll_pkttype = PACKET_OTHERHOST;
+ memcpy(sll.sll_addr, lldpaddr, ETH_ALEN);
+ if (sendto(s, sendbuf, len, 0, (struct sockaddr*)&sll, sizeof(sll)) < 0) {
+ fprintf(stderr, "LLDP sendto failed\n");
+ exit(1);
+ }
+}
+
+
+static void usage(const char *progname)
+{
+ fprintf(stderr, "usage: %s -i eth# -m 00:11:22:33:44:55 -s G0123456789\n",
+ progname);
+ exit(1);
+}
+
+
+int main(int argc, char *argv[])
+{
+ const char *macaddr = NULL;
+ const char *serial = NULL;
+ int c;
+ int s;
+
+ while ((c = getopt(argc, argv, "i:m:s:")) != -1) {
+ switch (c) {
+ case 'i':
+ if (ninterfaces == (MAXINTERFACES - 1)) {
+ usage(argv[0]);
+ }
+ ifnames[ninterfaces++] = optarg;
+ break;
+ case 'm':
+ macaddr = optarg;
+ break;
+ case 's':
+ serial = optarg;
+ break;
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+
+ if (ninterfaces == 0 || macaddr == NULL || serial == NULL) {
+ usage(argv[0]);
+ }
+
+ if ((s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) {
+ fprintf(stderr, "socket(PF_PACKET) failed\n");
+ exit(1);
+ }
+
+ while (1) {
+ int i;
+
+ for (i = 0; i < ninterfaces; ++i) {
+ if (ifnames[i] != NULL) {
+ size_t len = format_lldp_packet(macaddr, ifnames[i], serial);
+ send_lldp_packet(s, len, ifnames[i]);
+ }
+ usleep(10000 + (rand() % 80000));
+ }
+
+ usleep(500000 + (rand() % 1000000));
+ }
+
+ return 0;
+}
+#endif /* UNIT_TESTS */
diff --git a/cmds/gflldpd_test.cc b/cmds/gflldpd_test.cc
new file mode 100644
index 0000000..21f33df
--- /dev/null
+++ b/cmds/gflldpd_test.cc
@@ -0,0 +1,61 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2013 Keichi Takahashi keichi.t@me.com
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <netinet/if_ether.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <wvtest.h>
+
+
+#define UNIT_TESTS
+#include "gflldpd.c"
+
+
+WVTEST_MAIN("mac_str_to_bytes") {
+ uint8_t expected_mac[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
+ uint8_t mac[ETH_ALEN];
+
+ mac_str_to_bytes("00:11:22:33:44:55", mac);
+ WVPASSEQ(memcmp(mac, expected_mac, ETH_ALEN), 0);
+}
+
+
+WVTEST_MAIN("format_lldp_packet") {
+ size_t siz;
+ uint8_t expected[] = {
+ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e, 0x00, 0x11,
+ 0x22, 0x33, 0x44, 0x55, 0x88, 0xcc, 0x02, 0x07,
+ 0x04, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x04,
+ 0x07, 0x03, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
+ 0x06, 0x02, 0x00, 0x78, 0x08, 0x04, 0x65, 0x74,
+ 0x68, 0x30, 0x0a, 0x0b, 0x47, 0x30, 0x31, 0x32,
+ 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x00,
+ 0x00
+ };
+
+ siz = format_lldp_packet("00:11:22:33:44:55", "eth0", "G0123456789");
+ WVPASSEQ(siz, sizeof(expected));
+ WVPASSEQ(memcmp(sendbuf, expected, siz), 0);
+}
diff --git a/cmds/is-secure-boot.gfch100 b/cmds/is-secure-boot.gfch100
new file mode 120000
index 0000000..cf37783
--- /dev/null
+++ b/cmds/is-secure-boot.gfch100
@@ -0,0 +1 @@
+is-secure-boot.stub
\ No newline at end of file
diff --git a/cmds/is-secure-boot.gfrg240 b/cmds/is-secure-boot.gfrg240
new file mode 120000
index 0000000..cf37783
--- /dev/null
+++ b/cmds/is-secure-boot.gfrg240
@@ -0,0 +1 @@
+is-secure-boot.stub
\ No newline at end of file
diff --git a/cmds/is-secure-boot.gfch100 b/cmds/is-secure-boot.stub
similarity index 100%
rename from cmds/is-secure-boot.gfch100
rename to cmds/is-secure-boot.stub
diff --git a/cmds/statpitcher.cc b/cmds/statpitcher.cc
index 0a19443..27dd171 100644
--- a/cmds/statpitcher.cc
+++ b/cmds/statpitcher.cc
@@ -173,7 +173,7 @@
if (pipe) {
char buffer[128];
if (fgets(buffer, 128, pipe.get()) != NULL) {
- std::istringstream(buffer) >> ret;
+ std::istringstream(buffer) >> std::hex >> ret;
}
}
return ret;
diff --git a/conman/Makefile b/conman/Makefile
index 6126f84..2914b4a 100644
--- a/conman/Makefile
+++ b/conman/Makefile
@@ -9,7 +9,7 @@
echo 'echo "(gpylint-missing)" >&2'; \
fi \
)
-NOINSTALL=%_test.py options.py experiment.py experiment_testutils.py
+NOINSTALL=%_test.py options.py experiment.py experiment_testutils.py test_common.py
all:
diff --git a/conman/connection_manager.py b/conman/connection_manager.py
index b4c3887..326b946 100755
--- a/conman/connection_manager.py
+++ b/conman/connection_manager.py
@@ -26,6 +26,8 @@
import ratchet
import status
+logger = logging.getLogger(__name__)
+
try:
import monotime # pylint: disable=unused-import,g-import-not-at-top
except ImportError:
@@ -74,16 +76,16 @@
WIFI_SETCLIENT = ['wifi', 'setclient', '--persist']
WIFI_STOPCLIENT = ['wifi', 'stopclient', '--persist']
- def __init__(self, band, wifi, command_lines, wpa_control_interface):
+ def __init__(self, band, wifi, command_lines):
self.band = band
self.wifi = wifi
+ self.logger = self.wifi.logger.getChild(self.band)
self.command = command_lines.splitlines()
self.access_point_up = False
self.ssid = None
self.passphrase = None
self.interface_suffix = None
self.access_point = None
- self._wpa_control_interface = wpa_control_interface
binwifi_option_attrs = {
'-s': 'ssid',
@@ -106,16 +108,12 @@
if self.ssid is None:
raise ValueError('Command file does not specify SSID')
- if self.wifi.initial_ssid == self.ssid:
- logging.info('Connected to WLAN at startup')
+ if self.client_up:
+ self.logger.info('Connected to WLAN at startup')
@property
def client_up(self):
- wpa_status = self.wifi.wpa_status()
- return (wpa_status.get('wpa_state') == 'COMPLETED'
- # NONE indicates we're on a provisioning network; anything else
- # suggests we're already on the WLAN.
- and wpa_status.get('key_mgmt') != 'NONE')
+ return self.ssid and self.ssid == self.wifi.current_secure_ssid()
def start_access_point(self):
"""Start an access point."""
@@ -131,9 +129,9 @@
try:
subprocess.check_output(self.command, stderr=subprocess.STDOUT)
self.access_point_up = True
- logging.info('Started %s GHz AP', self.band)
+ self.logger.info('Started %s GHz AP', self.band)
except subprocess.CalledProcessError as e:
- logging.error('Failed to start access point: %s', e.output)
+ self.logger.error('Failed to start access point: %s', e.output)
def stop_access_point(self):
if not self.access_point_up:
@@ -146,24 +144,25 @@
try:
subprocess.check_output(command, stderr=subprocess.STDOUT)
self.access_point_up = False
- logging.info('Stopped %s GHz AP', self.band)
+ self.logger.info('Stopped %s GHz AP', self.band)
except subprocess.CalledProcessError as e:
- logging.error('Failed to stop access point: %s', e.output)
+ self.logger.error('Failed to stop access point: %s', e.output)
return
def start_client(self):
"""Join the WLAN as a client."""
if experiment.enabled('WifiNo2GClient') and self.band == '2.4':
- logging.info('WifiNo2GClient enabled; not starting 2.4 GHz client.')
+ self.logger.info('WifiNo2GClient enabled; not starting 2.4 GHz client.')
return
up = self.client_up
if up:
- logging.debug('Wifi client already started on %s GHz', self.band)
+ self.logger.debug('Wifi client already started on %s GHz', self.band)
return
if self._actually_start_client():
- self._post_start_client()
+ self.wifi.status.connected_to_wlan = True
+ self.logger.info('Started wifi client on %s GHz', self.band)
def _actually_start_client(self):
"""Actually run wifi setclient.
@@ -181,34 +180,26 @@
self.wifi.status.trying_wlan = True
subprocess.check_output(command, stderr=subprocess.STDOUT, env=env)
except subprocess.CalledProcessError as e:
- logging.error('Failed to start wifi client: %s', e.output)
+ self.logger.error('Failed to start wifi client: %s', e.output)
self.wifi.status.wlan_failed = True
return False
return True
- def _post_start_client(self):
- self.wifi.handle_wpa_events()
- self.wifi.status.connected_to_wlan = True
- logging.info('Started wifi client on %s GHz', self.band)
- self.wifi.attach_wpa_control(self._wpa_control_interface)
-
def stop_client(self):
if not self.client_up:
- logging.debug('Wifi client already stopped on %s GHz', self.band)
+ self.logger.debug('Wifi client already stopped on %s GHz', self.band)
return
- self.wifi.detach_wpa_control()
-
try:
subprocess.check_output(self.WIFI_STOPCLIENT + ['-b', self.band],
stderr=subprocess.STDOUT)
# TODO(rofrankel): Make this work for dual-radio devices.
self.wifi.status.connected_to_wlan = False
- logging.info('Stopped wifi client on %s GHz', self.band)
- self.wifi.handle_wpa_events()
+ self.logger.info('Stopped wifi client on %s GHz', self.band)
+ self.wifi.update()
except subprocess.CalledProcessError as e:
- logging.error('Failed to stop wifi client: %s', e.output)
+ self.logger.error('Failed to stop wifi client: %s', e.output)
class ConnectionManager(object):
@@ -242,7 +233,6 @@
tmp_dir='/tmp/conman',
config_dir='/config/conman',
moca_tmp_dir='/tmp/cwmp/monitoring/moca2',
- wpa_control_interface='/var/run/wpa_supplicant',
run_duration_s=1, interface_update_period=5,
wifi_scan_period_s=120, wlan_retry_s=120, associate_wait_s=15,
dhcp_wait_s=10, acs_connection_check_wait_s=1,
@@ -254,7 +244,6 @@
self._interface_status_dir = os.path.join(tmp_dir, 'interfaces')
self._status_dir = os.path.join(tmp_dir, 'status')
self._moca_tmp_dir = moca_tmp_dir
- self._wpa_control_interface = wpa_control_interface
self._run_duration_s = run_duration_s
self._interface_update_period = interface_update_period
self._wifi_scan_period_s = wifi_scan_period_s
@@ -273,7 +262,7 @@
self._interface_status_dir, self._moca_tmp_dir):
if not os.path.exists(directory):
os.makedirs(directory)
- logging.info('Created monitored directory: %s', directory)
+ logger.info('Created monitored directory: %s', directory)
acs_autoprov_filepath = os.path.join(self._tmp_dir,
'acs_autoprovisioning')
@@ -287,8 +276,8 @@
status_dir = os.path.join(self._status_dir, ifc.name)
if not os.path.exists(status_dir):
os.makedirs(status_dir)
- ifc.status = status.Status(status_dir)
- self._status = status.CompositeStatus(self._status_dir,
+ ifc.status = status.Status(ifc.name, status_dir)
+ self._status = status.CompositeStatus(__name__, self._status_dir,
[i.status for i in self.interfaces()])
wm = pyinotify.WatchManager()
@@ -310,17 +299,13 @@
self.ifplugd_action('eth0', ethernet_up)
self.bridge.ethernet = ethernet_up
- # Do the same for wifi interfaces , but rather than explicitly setting that
- # the wpa_supplicant link is up, attempt to attach to the wpa_supplicant
- # control interface.
+ # Do the same for wifi interfaces.
for wifi in self.wifi:
wifi_up = self.is_interface_up(wifi.name)
+ wifi.wpa_supplicant = wifi_up
if not os.path.exists(
os.path.join(self._interface_status_dir, wifi.name)):
self.ifplugd_action(wifi.name, wifi_up)
- if wifi_up:
- wifi.status.attached_to_wpa_supplicant = wifi.attach_wpa_control(
- self._wpa_control_interface)
for path, prefix in ((self._tmp_dir, self.GATEWAY_FILE_PREFIX),
(self._tmp_dir, self.SUBNET_FILE_PREFIX),
@@ -334,7 +319,7 @@
# the routing table.
for ifc in self.interfaces():
ifc.initialize()
- logging.info('%s initialized', ifc.name)
+ logger.info('%s initialized', ifc.name)
# Make sure no unwanted APs or clients are running.
for wifi in self.wifi:
@@ -343,20 +328,20 @@
if config:
if config.access_point and self.bridge.internet():
# If we have a config and want an AP, we don't want a client.
- logging.info('Stopping pre-existing %s client on %s',
- band, wifi.name)
+ logger.info('Stopping pre-existing %s client on %s',
+ band, wifi.name)
self._stop_wifi(band, False, True)
else:
# If we have a config but don't want an AP, make sure we aren't
# running one.
- logging.info('Stopping pre-existing %s AP on %s', band, wifi.name)
+ logger.info('Stopping pre-existing %s AP on %s', band, wifi.name)
self._stop_wifi(band, True, False)
break
else:
# If we have no config for this radio, neither a client nor an AP should
# be running.
- logging.info('Stopping pre-existing %s AP and clienton %s',
- band, wifi.name)
+ logger.info('Stopping pre-existing %s AP and clienton %s',
+ band, wifi.name)
self._stop_wifi(wifi.bands[0], True, True)
self._interface_update_counter = 0
@@ -438,8 +423,6 @@
while True:
self.run_once()
finally:
- for wifi in self.wifi:
- wifi.detach_wpa_control()
self.notifier.stop()
def run_once(self):
@@ -479,7 +462,7 @@
for wifi in self.wifi:
if self.currently_provisioning(wifi):
- logging.debug('Currently provisioning, nothing else to do.')
+ logger.debug('Currently provisioning, nothing else to do.')
continue
provisioning_failed = self.provisioning_failed(wifi)
@@ -510,22 +493,17 @@
if wlan_configuration.access_point_up:
continue_wifi = True
- if not wifi.attached():
- logging.debug('Attempting to attach to wpa control interface for %s',
- wifi.name)
- wifi.status.attached_to_wpa_supplicant = wifi.attach_wpa_control(
- self._wpa_control_interface)
- wifi.handle_wpa_events()
+ wifi.update()
if continue_wifi:
- logging.debug('Running AP on %s, nothing else to do.', wifi.name)
+ logger.debug('Running AP on %s, nothing else to do.', wifi.name)
continue
# If this interface is connected to the user's WLAN, there is nothing else
# to do.
if self._connected_to_wlan(wifi):
wifi.status.connected_to_wlan = True
- logging.debug('Connected to WLAN on %s, nothing else to do.', wifi.name)
+ logger.debug('Connected to WLAN on %s, nothing else to do.', wifi.name)
continue
# This interface is not connected to the WLAN, so scan for potential
@@ -533,7 +511,7 @@
if ((not self.acs() or provisioning_failed) and
not getattr(wifi, 'last_successful_bss_info', None) and
_gettime() > wifi.last_wifi_scan_time + self._wifi_scan_period_s):
- logging.debug('Performing scan on %s.', wifi.name)
+ logger.debug('Performing scan on %s.', wifi.name)
self._wifi_scan(wifi)
# Periodically retry rejoining the WLAN. If the WLAN configuration is
@@ -544,15 +522,15 @@
for band in wifi.bands:
wlan_configuration = self._wlan_configuration.get(band, None)
if wlan_configuration and _gettime() >= self._try_wlan_after[band]:
- logging.info('Trying to join WLAN on %s.', wifi.name)
+ logger.info('Trying to join WLAN on %s.', wifi.name)
wlan_configuration.start_client()
if self._connected_to_wlan(wifi):
- logging.info('Joined WLAN on %s.', wifi.name)
+ logger.info('Joined WLAN on %s.', wifi.name)
wifi.status.connected_to_wlan = True
self._try_wlan_after[band] = 0
break
else:
- logging.error('Failed to connect to WLAN on %s.', wifi.name)
+ logger.error('Failed to connect to WLAN on %s.', wifi.name)
wifi.status.connected_to_wlan = False
self._try_wlan_after[band] = _gettime() + self._wlan_retry_s
else:
@@ -562,10 +540,10 @@
# 1) The configuration didn't change, and we should retry connecting.
# 2) cwmpd isn't writing a configuration, possibly because the device
# isn't registered to any accounts.
- logging.debug('Unable to join WLAN on %s', wifi.name)
+ logger.debug('Unable to join WLAN on %s', wifi.name)
wifi.status.connected_to_wlan = False
if self.acs():
- logging.debug('Connected to ACS')
+ logger.debug('Connected to ACS')
if wifi.acs():
wifi.last_successful_bss_info = getattr(wifi,
@@ -576,8 +554,8 @@
now = _gettime()
if self._wlan_configuration:
- logging.info('ACS has not updated WLAN configuration; will retry '
- ' with old config.')
+ logger.info('ACS has not updated WLAN configuration; will retry '
+ ' with old config.')
for w in self.wifi:
for b in w.bands:
self._try_wlan_after[b] = now
@@ -587,18 +565,18 @@
elif (hasattr(wifi, 'complain_about_acs_at')
and now >= wifi.complain_about_acs_at):
wait = wifi.complain_about_acs_at - self.provisioning_since(wifi)
- logging.info('Can ping ACS, but no WLAN configuration for %ds.',
- wait)
+ logger.info('Can ping ACS, but no WLAN configuration for %ds.',
+ wait)
wifi.complain_about_acs_at += wait
# If we didn't manage to join the WLAN, and we don't have an ACS
# connection or the ACS session failed, we should try another open AP.
if not self.acs() or provisioning_failed:
now = _gettime()
if self._connected_to_open(wifi) and not provisioning_failed:
- logging.debug('Waiting for provisioning for %ds.',
- now - self.provisioning_since(wifi))
+ logger.debug('Waiting for provisioning for %ds.',
+ now - self.provisioning_since(wifi))
else:
- logging.debug('Not connected to ACS or provisioning failed')
+ logger.debug('Not connected to ACS or provisioning failed')
self._try_next_bssid(wifi)
time.sleep(max(0, self._run_duration_s - (_gettime() - start_time)))
@@ -662,8 +640,8 @@
if lowest_metric_interface:
ip = lowest_metric_interface[1].get_ip_address()
ip_line = '%s %s\n' % (ip, HOSTNAME) if ip else ''
- logging.info('Lowest metric default route is on dev %r',
- lowest_metric_interface[1].name)
+ logger.info('Lowest metric default route is on dev %r',
+ lowest_metric_interface[1].name)
new_tmp_hosts = '%s127.0.0.1 localhost' % ip_line
@@ -712,7 +690,7 @@
if e.errno == errno.ENOENT:
# Logging about failing to open .tmp files results in spammy logs.
if not filename.endswith('.tmp'):
- logging.error('Not a file: %s', filepath)
+ logger.error('Not a file: %s', filepath)
return
else:
raise
@@ -721,10 +699,10 @@
if filename == self.ETHERNET_STATUS_FILE:
try:
self.bridge.ethernet = bool(int(contents))
- logging.info('Ethernet %s', 'up' if self.bridge.ethernet else 'down')
+ logger.info('Ethernet %s', 'up' if self.bridge.ethernet else 'down')
except ValueError:
- logging.error('Status file contents should be 0 or 1, not %s',
- contents)
+ logger.error('Status file contents should be 0 or 1, not %s',
+ contents)
return
elif path == self._config_dir:
@@ -735,8 +713,7 @@
wifi = self.wifi_for_band(band)
if wifi:
self._update_wlan_configuration(
- self.WLANConfiguration(band, wifi, contents,
- self._wpa_control_interface))
+ self.WLANConfiguration(band, wifi, contents))
elif filename.startswith(self.ACCESS_POINT_FILE_PREFIX):
match = re.match(self.ACCESS_POINT_FILE_REGEXP, filename)
if match:
@@ -744,7 +721,7 @@
wifi = self.wifi_for_band(band)
if wifi and band in self._wlan_configuration:
self._wlan_configuration[band].access_point = True
- logging.info('AP enabled for %s GHz', band)
+ logger.info('AP enabled for %s GHz', band)
elif path == self._tmp_dir:
if filename.startswith(self.GATEWAY_FILE_PREFIX):
@@ -756,16 +733,16 @@
ifc = self.interface_by_name(interface_name)
if ifc:
ifc.set_gateway_ip(contents)
- logging.info('Received gateway %r for interface %s', contents,
- ifc.name)
+ logger.info('Received gateway %r for interface %s', contents,
+ ifc.name)
if filename.startswith(self.SUBNET_FILE_PREFIX):
interface_name = filename.split(self.SUBNET_FILE_PREFIX)[-1]
ifc = self.interface_by_name(interface_name)
if ifc:
ifc.set_subnet(contents)
- logging.info('Received subnet %r for interface %s', contents,
- ifc.name)
+ logger.info('Received subnet %r for interface %s', contents,
+ ifc.name)
elif path == self._moca_tmp_dir:
match = re.match(r'^%s\d+$' % self.MOCA_NODE_FILE_PREFIX, filename)
@@ -773,7 +750,7 @@
try:
json_contents = json.loads(contents)
except ValueError:
- logging.error('Cannot parse %s as JSON.', filepath)
+ logger.error('Cannot parse %s as JSON.', filepath)
return
node = json_contents['NodeId']
had_moca = self.bridge.moca
@@ -795,9 +772,9 @@
if band in wifi.bands:
return wifi
- logging.error('No wifi interface for %s GHz. wlan interfaces:\n%s',
- band, '\n'.join('%s: %r' %
- (w.name, w.bands) for w in self.wifi))
+ logger.error('No wifi interface for %s GHz. wlan interfaces:\n%s',
+ band, '\n'.join('%s: %r' %
+ (w.name, w.bands) for w in self.wifi))
def ifplugd_action(self, interface_name, up):
subprocess.call(self.IFPLUGD_ACTION + [interface_name,
@@ -805,13 +782,13 @@
def _wifi_scan(self, wifi):
"""Perform a wifi scan and update wifi.cycler."""
- logging.info('Scanning on %s...', wifi.name)
+ logger.info('Scanning on %s...', wifi.name)
wifi.last_wifi_scan_time = _gettime()
subprocess.call(self.IFUP + [wifi.name])
# /bin/wifi takes a --band option but then finds the right interface for it,
# so it's okay to just pick the first band here.
items = self._find_bssids(wifi.bands[0])
- logging.info('Done scanning on %s', wifi.name)
+ logger.info('Done scanning on %s', wifi.name)
if not hasattr(wifi, 'cycler'):
wifi.cycler = cycler.AgingPriorityCycler(
cycle_length_s=self._bssid_cycle_length_s)
@@ -839,17 +816,16 @@
last_successful_bss_info = getattr(wifi, 'last_successful_bss_info', None)
bss_info = last_successful_bss_info or wifi.cycler.next()
if bss_info is not None:
- logging.info('Attempting to connect to SSID %s (%s) for provisioning',
- bss_info.ssid, bss_info.bssid)
+ logger.info('Attempting to connect to SSID %s (%s) for provisioning',
+ bss_info.ssid, bss_info.bssid)
self.start_provisioning(wifi)
connected = self._try_bssid(wifi, bss_info)
if connected:
- wifi.attach_wpa_control(self._wpa_control_interface)
- wifi.handle_wpa_events()
+ wifi.update()
wifi.status.connected_to_open = True
now = _gettime()
wifi.complain_about_acs_at = now + 5
- logging.info('Attempting to provision via SSID %s', bss_info.ssid)
+ logger.info('Attempting to provision via SSID %s', bss_info.ssid)
self._try_to_upload_logs = True
# If we can no longer connect to this, it's no longer successful.
else:
@@ -863,7 +839,7 @@
# Relatedly, once we find ACS access on an open network we may want to
# save that SSID/BSSID and that first in future. If we do that then we
# can declare that provisioning has failed much more aggressively.
- logging.info('Ran out of BSSIDs to try on %s', wifi.name)
+ logger.info('Ran out of BSSIDs to try on %s', wifi.name)
wifi.status.provisioning_failed = True
return False
@@ -890,7 +866,7 @@
band = wlan_configuration.band
current = self._wlan_configuration.get(band, None)
if current is None or wlan_configuration.command != current.command:
- logging.debug('Received new WLAN configuration for band %s', band)
+ logger.debug('Received new WLAN configuration for band %s', band)
if current is not None:
wlan_configuration.access_point = current.access_point
else:
@@ -901,7 +877,7 @@
wlan_configuration.access_point = os.path.exists(ap_file)
self._wlan_configuration[band] = wlan_configuration
self.wifi_for_band(band).status.have_config = True
- logging.info('Updated WLAN configuration for %s GHz', band)
+ logger.info('Updated WLAN configuration for %s GHz', band)
self._update_access_point(wlan_configuration)
def _update_access_point(self, wlan_configuration):
@@ -938,7 +914,7 @@
try:
self._binwifi(*full_command)
except subprocess.CalledProcessError as e:
- logging.error('wifi %s failed: "%s"', ' '.join(full_command), e.output)
+ logger.error('wifi %s failed: "%s"', ' '.join(full_command), e.output)
def _binwifi(self, *command):
"""Test seam for calls to /bin/wifi.
@@ -956,13 +932,13 @@
stderr=subprocess.STDOUT)
def _try_upload_logs(self):
- logging.info('Attempting to upload logs')
+ logger.info('Attempting to upload logs')
if subprocess.call(self.UPLOAD_LOGS_AND_WAIT) != 0:
- logging.error('Failed to upload logs')
+ logger.error('Failed to upload logs')
def cwmp_wakeup(self):
if subprocess.call(self.CWMP_WAKEUP) != 0:
- logging.error('cwmp wakeup failed')
+ logger.error('cwmp wakeup failed')
def start_provisioning(self, wifi):
wifi.set_gateway_ip(None)
@@ -975,12 +951,12 @@
if wifi.provisioning_ratchet.done_after:
wifi.status.provisioning_completed = True
wifi.provisioning_ratchet.stop()
- logging.info('%s successfully provisioned', wifi.name)
+ logger.info('%s successfully provisioned', wifi.name)
return False
except ratchet.TimeoutException:
wifi.status.provisioning_failed = True
- logging.info('%s failed to provision: %s', wifi.name,
- wifi.provisioning_ratchet.current_step().name)
+ logger.info('%s failed to provision: %s', wifi.name,
+ wifi.provisioning_ratchet.current_step().name)
return True
def provisioning_completed(self, wifi):
@@ -999,7 +975,7 @@
try:
return subprocess.check_output(['wifi', 'show'])
except subprocess.CalledProcessError as e:
- logging.error('Failed to call "wifi show": %s', e)
+ logger.error('Failed to call "wifi show": %s', e)
return ''
@@ -1007,7 +983,7 @@
try:
return subprocess.check_output(['get-quantenna-interfaces']).split()
except subprocess.CalledProcessError:
- logging.fatal('Failed to call get-quantenna-interfaces')
+ logger.fatal('Failed to call get-quantenna-interfaces')
raise
diff --git a/conman/connection_manager_test.py b/conman/connection_manager_test.py
index 22cf89f..e9807cd 100755
--- a/conman/connection_manager_test.py
+++ b/conman/connection_manager_test.py
@@ -15,9 +15,11 @@
import interface_test
import iw
import status
+import test_common
from wvtest import wvtest
-logging.basicConfig(level=logging.DEBUG)
+logger = logging.getLogger(__name__)
+
FAKE_MOCA_NODE1_FILE = """{
"NodeId": 1,
@@ -66,7 +68,7 @@
"""
-@wvtest.wvtest
+@test_common.wvtest
def get_client_interfaces_test():
"""Test get_client_interfaces."""
subprocess.reset()
@@ -96,7 +98,7 @@
{'wcli0': {'frenzy': True, 'bands': set(['5'])}})
-@wvtest.wvtest
+@test_common.wvtest
def WLANConfigurationParseTest(): # pylint: disable=invalid-name
"""Test WLANConfiguration parsing."""
subprocess.reset()
@@ -106,7 +108,7 @@
'--bridge=br0', '-s', 'my ssid=1', '--interface-suffix', '_suffix',
])
config = connection_manager.WLANConfiguration(
- '5', interface_test.Wifi('wcli0', 20), cmd, None)
+ '5', interface_test.Wifi('wcli0', 20), cmd)
wvtest.WVPASSEQ('my ssid=1', config.ssid)
wvtest.WVPASSEQ('abcdWIFI_PSK=qwer', config.passphrase)
@@ -157,10 +159,6 @@
subprocess.mock('wifi', 'remote_ap', band=band, ssid=ssid, psk=psk,
bssid='00:00:00:00:00:00')
- # Also create the wpa_supplicant socket to which to attach.
- open(os.path.join(kwargs['wpa_control_interface'], interface_name),
- 'w')
-
super(ConnectionManager, self).__init__(*args, **kwargs)
# Just looking for last_wifi_scan_time to change doesn't work because the
@@ -206,7 +204,7 @@
self.run_once()
def run_until_scan(self, band):
- logging.debug('running until scan on band %r', band)
+ logger.debug('running until scan on band %r', band)
wifi = self.wifi_for_band(band)
wifi_scan_counter = wifi.wifi_scan_counter
while wifi_scan_counter == wifi.wifi_scan_counter:
@@ -261,7 +259,6 @@
moca_tmp_dir = tempfile.mkdtemp()
wpa_control_interface = tempfile.mkdtemp()
subprocess.mock('wifi', 'wpa_path', wpa_control_interface)
- FrenzyWifi.WPACtrl.WIFIINFO_PATH = tempfile.mkdtemp()
connection_manager.CWMP_PATH = tempfile.mkdtemp()
subprocess.set_conman_paths(tmp_dir, config_dir,
connection_manager.CWMP_PATH)
@@ -276,7 +273,6 @@
c = ConnectionManager(tmp_dir=tmp_dir,
config_dir=config_dir,
moca_tmp_dir=moca_tmp_dir,
- wpa_control_interface=wpa_control_interface,
run_duration_s=run_duration_s,
interface_update_period=interface_update_period,
wlan_retry_s=0,
@@ -291,7 +287,7 @@
f(c)
except Exception:
- logging.error('Uncaught exception!')
+ logger.error('Uncaught exception!')
traceback.print_exc()
raise
finally:
@@ -301,7 +297,6 @@
shutil.rmtree(config_dir)
shutil.rmtree(moca_tmp_dir)
shutil.rmtree(wpa_control_interface)
- shutil.rmtree(FrenzyWifi.WPACtrl.WIFIINFO_PATH)
shutil.rmtree(connection_manager.CWMP_PATH)
actual_test.func_name = f.func_name
@@ -478,6 +473,7 @@
ssid = 'wlan2'
psk = 'password2'
subprocess.mock('cwmp', band, ssid=ssid, psk=psk)
+ # Overwrites previous one due to same BSSID.
subprocess.mock('wifi', 'remote_ap',
bssid='11:22:33:44:55:66',
ssid=ssid, psk=psk, band=band, security='WPA2')
@@ -487,10 +483,6 @@
wvtest.WVPASS(c._connected_to_open(c.wifi_for_band(band)))
wvtest.WVPASSEQ(c.wifi_for_band(band).last_attempted_bss_info.ssid, 's2')
- # Overwrites previous one due to same BSSID.
- subprocess.mock('wifi', 'remote_ap',
- bssid='11:22:33:44:55:66',
- ssid=ssid, psk=psk, band=band, security='WPA2')
# Run once for cwmp wakeup to get called, then once more for the new config to
# be received.
c.run_once()
@@ -761,43 +753,43 @@
wvtest.WVPASS(c.has_status_files([status.P.PROVISIONING_COMPLETED]))
-@wvtest.wvtest
+@test_common.wvtest
@connection_manager_test(WIFI_SHOW_OUTPUT_MARVELL8897)
def connection_manager_test_generic_marvell8897_2g(c):
connection_manager_test_generic(c, '2.4')
-@wvtest.wvtest
+@test_common.wvtest
@connection_manager_test(WIFI_SHOW_OUTPUT_MARVELL8897)
def connection_manager_test_generic_marvell8897_5g(c):
connection_manager_test_generic(c, '5')
-@wvtest.wvtest
+@test_common.wvtest
@connection_manager_test(WIFI_SHOW_OUTPUT_ATH9K_ATH10K)
def connection_manager_test_generic_ath9k_ath10k_2g(c):
connection_manager_test_generic(c, '2.4')
-@wvtest.wvtest
+@test_common.wvtest
@connection_manager_test(WIFI_SHOW_OUTPUT_ATH9K_ATH10K)
def connection_manager_test_generic_ath9k_ath10k_5g(c):
connection_manager_test_generic(c, '5')
-@wvtest.wvtest
+@test_common.wvtest
@connection_manager_test(WIFI_SHOW_OUTPUT_ATH9K_FRENZY)
def connection_manager_test_generic_ath9k_frenzy_2g(c):
connection_manager_test_generic(c, '2.4')
-@wvtest.wvtest
+@test_common.wvtest
@connection_manager_test(WIFI_SHOW_OUTPUT_ATH9K_FRENZY)
def connection_manager_test_generic_ath9k_frenzy_5g(c):
connection_manager_test_generic(c, '5')
-@wvtest.wvtest
+@test_common.wvtest
@connection_manager_test(WIFI_SHOW_OUTPUT_FRENZY)
def connection_manager_test_generic_frenzy_5g(c):
connection_manager_test_generic(c, '5')
@@ -899,13 +891,13 @@
wvtest.WVPASS(subprocess.upload_logs_and_wait.uploaded_logs())
-@wvtest.wvtest
+@test_common.wvtest
@connection_manager_test(WIFI_SHOW_OUTPUT_ATH9K_ATH10K)
def connection_manager_test_dual_band_two_radios_ath9k_ath10k(c):
connection_manager_test_dual_band_two_radios(c)
-@wvtest.wvtest
+@test_common.wvtest
@connection_manager_test(WIFI_SHOW_OUTPUT_ATH9K_FRENZY)
def connection_manager_test_dual_band_two_radios_ath9k_frenzy(c):
connection_manager_test_dual_band_two_radios(c)
@@ -991,13 +983,13 @@
wvtest.WVPASS(subprocess.upload_logs_and_wait.uploaded_logs())
-@wvtest.wvtest
+@test_common.wvtest
@connection_manager_test(WIFI_SHOW_OUTPUT_MARVELL8897)
def connection_manager_test_dual_band_one_radio_marvell8897(c):
connection_manager_test_dual_band_one_radio(c)
-@wvtest.wvtest
+@test_common.wvtest
@connection_manager_test(WIFI_SHOW_OUTPUT_MARVELL8897_NO_5GHZ)
def connection_manager_test_marvell8897_no_5ghz(c):
"""Test ConnectionManager for the case documented in b/27328894.
@@ -1043,7 +1035,7 @@
wvtest.WVPASS(c.wifi_for_band('2.4').current_routes())
-@wvtest.wvtest
+@test_common.wvtest
@connection_manager_test(WIFI_SHOW_OUTPUT_MARVELL8897,
__test_interfaces_already_up=['eth0', 'wcli0'])
def connection_manager_test_wifi_already_up(c):
@@ -1056,7 +1048,7 @@
wvtest.WVPASS(c.wifi_for_band('2.4').current_routes())
-@wvtest.wvtest
+@test_common.wvtest
@connection_manager_test(WIFI_SHOW_OUTPUT_MARVELL8897, wlan_configs={'5': True})
def connection_manager_one_radio_marvell8897_existing_config_5g_ap(c):
wvtest.WVPASSEQ(len(c._binwifi_commands), 1)
@@ -1064,7 +1056,7 @@
c._binwifi_commands[0])
-@wvtest.wvtest
+@test_common.wvtest
@connection_manager_test(WIFI_SHOW_OUTPUT_MARVELL8897,
wlan_configs={'5': False})
def connection_manager_one_radio_marvell8897_existing_config_5g_no_ap(c):
@@ -1073,7 +1065,7 @@
c._binwifi_commands[0])
-@wvtest.wvtest
+@test_common.wvtest
@connection_manager_test(WIFI_SHOW_OUTPUT_ATH9K_ATH10K,
wlan_configs={'5': True})
def connection_manager_two_radios_ath9k_ath10k_existing_config_5g_ap(c):
@@ -1083,7 +1075,7 @@
in c._binwifi_commands)
-@wvtest.wvtest
+@test_common.wvtest
@connection_manager_test(WIFI_SHOW_OUTPUT_MARVELL8897)
def connection_manager_conman_no_2g_wlan(c):
unused_raii = experiment_testutils.MakeExperimentDirs()
diff --git a/conman/cycler_test.py b/conman/cycler_test.py
index de1e6c0..1493a83 100755
--- a/conman/cycler_test.py
+++ b/conman/cycler_test.py
@@ -5,10 +5,11 @@
import time
import cycler
+import test_common
from wvtest import wvtest
-@wvtest.wvtest
+@test_common.wvtest
def cycler_test():
c = cycler.AgingPriorityCycler()
wvtest.WVPASS(c.next() is None)
diff --git a/conman/interface.py b/conman/interface.py
index b741555..245ca27 100755
--- a/conman/interface.py
+++ b/conman/interface.py
@@ -7,12 +7,7 @@
import re
import subprocess
-# This has to be called before another module calls it with a higher log level.
-# pylint: disable=g-import-not-at-top
-logging.basicConfig(level=logging.DEBUG)
-
import experiment
-import wpactrl
METRIC_5GHZ = 20
METRIC_24GHZ_5GHZ = 21
@@ -37,6 +32,7 @@
def __init__(self, name, base_metric):
self.name = name
+ self.logger = logging.getLogger(self.name)
# Currently connected links for this interface, e.g. ethernet.
self.links = set()
@@ -68,18 +64,18 @@
"""
# Until initialized, we want to act as if the interface is down.
if not self._initialized:
- logging.info('%s not initialized; not running connection_check%s',
- self.name, ' (ACS)' if check_acs else '')
+ self.logger.info('not initialized; not running connection_check%s',
+ ' (ACS)' if check_acs else '')
return None
if not self.links:
- logging.info('Connection check for %s failed due to no links', self.name)
+ self.logger.info('Connection check failed due to no links')
return False
- logging.debug('Gateway IP for %s is %s', self.name, self._gateway_ip)
+ self.logger.debug('Gateway IP is %s', self._gateway_ip)
if self._gateway_ip is None:
- logging.info('Connection check%s for %s failed due to no gateway IP',
- ' (ACS)' if check_acs else '', self.name)
+ self.logger.info('Connection check%s failed due to no gateway IP',
+ ' (ACS)' if check_acs else '')
return False
self.add_routes()
@@ -92,10 +88,9 @@
with open(os.devnull, 'w') as devnull:
result = subprocess.call(cmd, stdout=devnull, stderr=devnull) == 0
- logging.info('Connection check%s for %s %s',
- ' (ACS)' if check_acs else '',
- self.name,
- 'passed' if result else 'failed')
+ self.logger.info('Connection check%s %s',
+ ' (ACS)' if check_acs else '',
+ 'passed' if result else 'failed')
return result
@@ -120,7 +115,7 @@
Remove any stale routes and add any missing desired routes.
"""
if self.metric is None:
- logging.info('Cannot add route for %s without a metric.', self.name)
+ self.logger.info('Cannot add route without a metric.')
return
# If the current routes are the same, there is nothing to do. If either
@@ -133,7 +128,7 @@
if self._subnet:
if ((subnet.get('route', None), subnet.get('metric', None)) !=
(self._subnet, str(self.metric))):
- logging.debug('Adding subnet route for dev %s', self.name)
+ self.logger.debug('Adding subnet route')
to_add.append(('subnet', ('add', self._subnet, 'dev', self.name,
'metric', str(self.metric))))
subnet = self._subnet
@@ -146,7 +141,7 @@
if (subnet and
(default.get('via', None), default.get('metric', None)) !=
(self._gateway_ip, str(self.metric))):
- logging.debug('Adding default route for dev %s', self.name)
+ self.logger.debug('Adding default route')
to_add.append(('default',
('add', 'default', 'via', self._gateway_ip,
'dev', self.name, 'metric', str(self.metric))))
@@ -155,7 +150,7 @@
# RFC2365 multicast route.
if current.get('multicast', {}).get('metric', None) != str(self.metric):
- logging.debug('Adding multicast route for dev %s', self.name)
+ self.logger.debug('Adding multicast route')
to_add.append(('multicast', ('add', RFC2385_MULTICAST_ROUTE,
'dev', self.name,
'metric', str(self.metric))))
@@ -185,7 +180,7 @@
# Use a sorted list to ensure that default comes before subnet.
for route_type in sorted(list(args)):
while route_type in self.current_routes():
- logging.debug('Deleting %s route for dev %s', route_type, self.name)
+ self.logger.debug('Deleting %s route', route_type)
self._ip_route('del', self.current_routes()[route_type]['route'],
'dev', self.name)
@@ -223,23 +218,23 @@
def _ip_route(self, *args):
if not self._initialized:
- logging.info('Not initialized, not running %s %s',
- ' '.join(self.IP_ROUTE), ' '.join(args))
+ self.logger.info('Not initialized, not running %s %s',
+ ' '.join(self.IP_ROUTE), ' '.join(args))
return ''
try:
- logging.debug('%s calling ip route %s', self.name, ' '.join(args))
+ self.logger.debug('calling ip route %s', ' '.join(args))
return subprocess.check_output(self.IP_ROUTE + list(args))
except subprocess.CalledProcessError as e:
- logging.error('Failed to call "ip route" with args %r: %s', args,
- e.message)
+ self.logger.error('Failed to call "ip route" with args %r: %s', args,
+ e.message)
return ''
def _ip_addr_show(self):
try:
return subprocess.check_output(self.IP_ADDR_SHOW + [self.name])
except subprocess.CalledProcessError as e:
- logging.error('Could not get IP address for %s: %s', self.name, e.message)
+ self.logger.error('Could not get IP address: %s', e.message)
return None
def get_ip_address(self):
@@ -248,12 +243,12 @@
return match and match.group('IP') or None
def set_gateway_ip(self, gateway_ip):
- logging.info('New gateway IP %s for %s', gateway_ip, self.name)
+ self.logger.info('New gateway IP %s', gateway_ip)
self._gateway_ip = gateway_ip
self.update_routes(expire_cache=True)
def set_subnet(self, subnet):
- logging.info('New subnet %s for %s', subnet, self.name)
+ self.logger.info('New subnet %s', subnet)
self._subnet = subnet
self.update_routes(expire_cache=True)
@@ -265,10 +260,10 @@
had_links = bool(self.links)
if is_up:
- logging.info('%s gained link %s', self.name, link)
+ self.logger.info('gained link %s', link)
self.links.add(link)
else:
- logging.info('%s lost link %s', self.name, link)
+ self.logger.info('lost link %s', link)
self.links.remove(link)
# If a link goes away, we may have lost access to something but not gained
@@ -283,7 +278,7 @@
self.update_routes(expire_cache=False)
def expire_connection_status_cache(self):
- logging.debug('Expiring connection status cache for %s', self.name)
+ self.logger.debug('Expiring connection status cache')
self._has_internet = self._has_acs = None
def update_routes(self, expire_cache=True):
@@ -297,7 +292,7 @@
expire_cache: If true, force a recheck of connection status before
deciding how to prioritize routes.
"""
- logging.debug('Updating routes for %s', self.name)
+ self.logger.debug('Updating routes')
if expire_cache:
self.expire_connection_status_cache()
@@ -319,7 +314,7 @@
"""
if not self._initialized:
return
- logging.info('%s routes have normal priority', self.name)
+ self.logger.info('routes have normal priority')
self.metric_offset = 0
self.add_routes()
@@ -331,7 +326,7 @@
"""
if not self._initialized:
return
- logging.info('%s routes have low priority', self.name)
+ self.logger.info('routes have low priority')
self.metric_offset = 50
self.add_routes()
@@ -402,9 +397,10 @@
failure_s = self._acs_session_failure_s()
if (experiment.enabled('WifiSimulateWireless')
and failure_s < MAX_ACS_FAILURE_S):
- logging.info('WifiSimulateWireless: failing bridge connection check%s '
- '(no ACS contact for %d seconds, max %d seconds)',
- ' (ACS)' if check_acs else '', failure_s, MAX_ACS_FAILURE_S)
+ self.logger.info('WifiSimulateWireless: failing bridge connection check%s'
+ ' (no ACS contact for %d seconds, max %d seconds)',
+ ' (ACS)' if check_acs else '', failure_s,
+ MAX_ACS_FAILURE_S)
return False
return super(Bridge, self)._connection_check(check_acs)
@@ -428,57 +424,19 @@
class Wifi(Interface):
"""Represents a wireless interface."""
- WPA_EVENT_RE = re.compile(r'<\d+>CTRL-EVENT-(?P<event>[A-Z\-]+).*')
- # pylint: disable=invalid-name
- WPACtrl = wpactrl.WPACtrl
-
def __init__(self, *args, **kwargs):
self.bands = kwargs.pop('bands', [])
super(Wifi, self).__init__(*args, **kwargs)
- self._wpa_control = None
- self.initial_ssid = None
@property
def wpa_supplicant(self):
+ self.update()
return 'wpa_supplicant' in self.links
@wpa_supplicant.setter
def wpa_supplicant(self, is_up):
self._set_link_status('wpa_supplicant', is_up)
- def attached(self):
- return self._wpa_control and self._wpa_control.attached
-
- def attach_wpa_control(self, path):
- """Attach to the wpa_supplicant control interface.
-
- Args:
- path: The path containing the wpa_supplicant control interface socket.
-
- Returns:
- Whether attaching was successful.
- """
- if self.attached():
- return True
-
- socket = os.path.join(path, self.name)
- logging.debug('%s socket is %s', self.name, socket)
- try:
- self._wpa_control = self.get_wpa_control(socket)
- self._wpa_control.attach()
- logging.debug('%s successfully attached', self.name)
- except (wpactrl.error, OSError) as e:
- logging.error('Error attaching to wpa_supplicant: %s', e)
- return False
-
- status = self.wpa_status()
- logging.debug('%s status after attaching is %s', self.name, status)
- self.wpa_supplicant = status.get('wpa_state') == 'COMPLETED'
- if not self._initialized:
- self.initial_ssid = status.get('ssid')
-
- return True
-
def wpa_status(self):
"""Parse the STATUS response from the wpa_supplicant control interface.
@@ -488,82 +446,40 @@
"""
status = {}
- if self.attached():
- lines = []
- try:
- lines = self._wpa_control.request('STATUS').splitlines()
- except (wpactrl.error, OSError) as e:
- logging.error('wpa_control STATUS request failed %s args %s',
- e.message, e.args)
- lines = self.wpa_cli_status().splitlines()
- for line in lines:
- if '=' not in line:
- continue
- k, v = line.strip().split('=', 1)
- status[k] = v
+ try:
+ lines = subprocess.check_output(['wpa_cli', '-i', self.name,
+ 'status']).splitlines()
+ except subprocess.CalledProcessError:
+ self.logger.error('wpa_cli status request failed')
+ return {}
- logging.debug('wpa_status is %r', status)
+ for line in lines:
+ if '=' not in line:
+ continue
+ k, v = line.strip().split('=', 1)
+ status[k] = v
+
return status
- def get_wpa_control(self, socket):
- return self.WPACtrl(socket)
-
- def detach_wpa_control(self):
- if self.attached():
- try:
- self._wpa_control.detach()
- except (wpactrl.error, OSError):
- logging.error('Failed to detach from wpa_supplicant interface. This '
- 'may mean something else killed wpa_supplicant.')
- self._wpa_control = None
-
- self.wpa_supplicant = False
-
- def handle_wpa_events(self):
- if not self.attached():
- self.wpa_supplicant = False
- return
-
- # b/31261343: Make sure we didn't miss wpa_supplicant being up.
+ def update(self):
self.wpa_supplicant = self.wpa_status().get('wpa_state', '') == 'COMPLETED'
- while self._wpa_control.pending():
- match = self.WPA_EVENT_RE.match(self._wpa_control.recv())
- if match:
- event = match.group('event')
- logging.debug('%s got wpa_supplicant event %s', self.name, event)
- if event == 'CONNECTED':
- self.wpa_supplicant = True
- elif event in ('DISCONNECTED', 'TERMINATING', 'ASSOC-REJECT',
- 'SSID-TEMP-DISABLED', 'AUTH-REJECT'):
- self.wpa_supplicant = False
- if event == 'TERMINATING':
- self.detach_wpa_control()
- break
-
- self.update_routes()
-
- def initialize(self):
- """Unset self.initial_ssid, which is only relevant during initialization."""
- self.initial_ssid = None
- super(Wifi, self).initialize()
-
def connected_to_open(self):
status = self.wpa_status()
return (status.get('wpa_state', None) == 'COMPLETED' and
status.get('key_mgmt', None) == 'NONE')
- # TODO(rofrankel): Remove this if and when the wpactrl failures are fixed.
- def wpa_cli_status(self):
- """Fallback for wpa_supplicant control interface status requests."""
- try:
- return subprocess.check_output(['wpa_cli', '-i', self.name, 'status'])
- except subprocess.CalledProcessError:
- logging.error('wpa_cli status request failed')
- return ''
+ def current_secure_ssid(self):
+ """Returns SSID if connected to a secure network, False otherwise."""
+ status = self.wpa_status()
+ return (status.get('wpa_state', None) == 'COMPLETED' and
+ # NONE indicates we're on a provisioning network; anything else
+ # suggests we're already on the WLAN.
+ status.get('key_mgmt', None) != 'NONE' and
+ status.get('ssid'))
-class FrenzyWPACtrl(object):
+class FrenzyWifi(Wifi):
"""A WPACtrl for Frenzy devices.
Implements the same functions used on the normal WPACtrl, using a combination
@@ -571,100 +487,34 @@
diffing saved state with current system state.
"""
- WIFIINFO_PATH = '/tmp/wifi/wifiinfo'
-
- def __init__(self, socket):
- self.ctrl_iface_path, self._interface = os.path.split(socket)
-
- # State from QCSAPI and wifi_files.
- self._client_mode = False
- self._ssid = None
- self._status = None
- self._security = None
-
- self._events = []
-
def _qcsapi(self, *command):
try:
return subprocess.check_output(['qcsapi'] + list(command)).strip()
except subprocess.CalledProcessError as e:
- logging.error('QCSAPI call failed: %s: %s', e, e.output)
+ self.logger.error('QCSAPI call failed: %s: %s', e, e.output)
raise
- def attach(self):
- self._update()
-
- @property
- def attached(self):
- return self._client_mode
-
- def detach(self):
- self._events = []
- raise wpactrl.error('Real WPACtrl always raises this when detaching.')
-
- def pending(self):
- self._update()
- return bool(self._events)
-
- def _update(self):
+ def wpa_status(self):
"""Generate and cache events, update state."""
try:
client_mode = self._qcsapi('get_mode', 'wifi0') == 'Station'
ssid = self._qcsapi('get_ssid', 'wifi0')
- status = self._qcsapi('get_status', 'wifi0')
security = (self._qcsapi('ssid_get_authentication_mode', 'wifi0', ssid)
if ssid else None)
except subprocess.CalledProcessError:
- # If QCSAPI failed, skip update.
- return
+ # If QCSAPI failed, don't crash.
+ return {}
- # If we have an SSID and are in client mode, and at least one of those is
- # new, then we have just connected.
- if client_mode and ssid and (not self._client_mode or ssid != self._ssid):
- self._events.append('<2>CTRL-EVENT-CONNECTED')
+ up = bool(client_mode and ssid)
+ self.wpa_supplicant = up
- # If we are in client mode but lost SSID, we disconnected.
- if client_mode and self._ssid and not ssid:
- self._events.append('<2>CTRL-EVENT-DISCONNECTED')
-
- # If there is an auth/assoc failure, then status (above) is 'Error'. We
- # really want the converse of this implication (i.e. that 'Error' implies an
- # auth/assoc failure), but due to limited documentation this will have to
- # do. It should be good enough: if something else causes get_status to
- # return 'Error', we are probably not connected, and we don't do anything
- # special with auth/assoc failures specifically.
- if client_mode and status == 'Error' and self._status != 'Error':
- self._events.append('<2>CTRL-EVENT-SSID-TEMP-DISABLED')
-
- # If we left client mode, wpa_supplicant has terminated.
- if self._client_mode and not client_mode:
- self._events.append('<2>CTRL-EVENT-TERMINATING')
-
- self._client_mode = client_mode
- self._ssid = ssid
- self._status = status
- self._security = security
-
- def recv(self):
- return self._events.pop(0)
-
- def request(self, request_type):
- """Partial implementation of WPACtrl.request."""
-
- if request_type != 'STATUS':
- return ''
-
- self._update()
-
- if not self._client_mode or not self._ssid:
- return ''
-
- return ('wpa_state=COMPLETED\nssid=%s\nkey_mgmt=%s' %
- (self._ssid, self._security or 'NONE'))
-
-
-class FrenzyWifi(Wifi):
- """Represents a Frenzy wireless interface."""
-
- # pylint: disable=invalid-name
- WPACtrl = FrenzyWPACtrl
+ if up:
+ return {
+ 'wpa_state': 'COMPLETED',
+ 'ssid': ssid,
+ 'key_mgmt': security or 'NONE',
+ }
+ else:
+ return {
+ 'wpa_state': 'SCANNING',
+ }
diff --git a/conman/interface_test.py b/conman/interface_test.py
index 14fb795..3ab58e6 100755
--- a/conman/interface_test.py
+++ b/conman/interface_test.py
@@ -2,19 +2,15 @@
"""Tests for connection_manager.py."""
-import logging
import os
import shutil
import subprocess
import tempfile
import time
-# This has to be called before another module calls it with a higher log level.
-# pylint: disable=g-import-not-at-top
-logging.basicConfig(level=logging.DEBUG)
-
import experiment_testutils
import interface
+import test_common
from wvtest import wvtest
@@ -57,7 +53,7 @@
pass
-@wvtest.wvtest
+@test_common.wvtest
def bridge_test():
"""Test Interface and Bridge."""
tmp_dir = tempfile.mkdtemp()
@@ -176,7 +172,6 @@
def generic_wifi_test(w, wpa_path):
# Not currently connected.
subprocess.wifi.WPA_PATH = wpa_path
- w.attach_wpa_control(wpa_path)
wvtest.WVFAIL(w.wpa_supplicant)
# wpa_supplicant connects.
@@ -186,42 +181,19 @@
bssid='00:00:00:00:00:00', connection_check_result='succeed')
subprocess.check_call(['wifi', 'setclient', '--ssid', ssid, '--band', '5'],
env={'WIFI_CLIENT_PSK': psk})
- wvtest.WVFAIL(w.wpa_supplicant)
- w.attach_wpa_control(wpa_path)
- w.handle_wpa_events()
wvtest.WVPASS(w.wpa_supplicant)
w.set_gateway_ip('192.168.1.1')
# wpa_supplicant disconnects.
subprocess.mock('wifi', 'disconnected_event', '5')
- w.handle_wpa_events()
wvtest.WVFAIL(w.wpa_supplicant)
- # Now, start over so we can test what happens when wpa_supplicant is already
- # connected when we attach.
- w.detach_wpa_control()
- w._initialized = False
- subprocess.check_call(['wifi', 'setclient', '--ssid', ssid, '--band', '5'],
- env={'WIFI_CLIENT_PSK': psk})
- w.attach_wpa_control(wpa_path)
-
- # wpa_supplicant was already connected when we attached.
- wvtest.WVPASS(w.wpa_supplicant)
- wvtest.WVPASSEQ(w.initial_ssid, ssid)
- w.initialize()
- wvtest.WVPASSEQ(w.initial_ssid, None)
-
- wvtest.WVPASSNE(w.wpa_status(), {})
- w._wpa_control.request_status_fails = True
- wvtest.WVPASSNE(w.wpa_status(), {})
-
# The wpa_supplicant process disconnects and terminates.
subprocess.check_call(['wifi', 'stopclient', '--band', '5'])
- w.handle_wpa_events()
wvtest.WVFAIL(w.wpa_supplicant)
-@wvtest.wvtest
+@test_common.wvtest
def wifi_test():
"""Test Wifi."""
w = Wifi('wcli0', '21')
@@ -241,7 +213,7 @@
shutil.rmtree(conman_path)
-@wvtest.wvtest
+@test_common.wvtest
def frenzy_wifi_test():
"""Test FrenzyWifi."""
w = FrenzyWifi('wlan0', '20')
@@ -254,17 +226,14 @@
subprocess.mock('wifi', 'interfaces',
subprocess.wifi.MockInterface(phynum='0', bands=['5'],
driver='frenzy'))
- FrenzyWifi.WPACtrl.WIFIINFO_PATH = wifiinfo_path = tempfile.mkdtemp()
-
generic_wifi_test(w, wpa_path)
finally:
shutil.rmtree(wpa_path)
shutil.rmtree(conman_path)
- shutil.rmtree(wifiinfo_path)
-@wvtest.wvtest
+@test_common.wvtest
def simulate_wireless_test():
"""Test the WifiSimulateWireless experiment."""
unused_raii = experiment_testutils.MakeExperimentDirs()
@@ -329,62 +298,5 @@
shutil.rmtree(interface.CWMP_PATH)
-@wvtest.wvtest
-def b31261343_test():
- """Test Wifi."""
- w = Wifi('wcli0', '21')
- w.initialize()
-
- try:
- wpa_path = tempfile.mkdtemp()
- conman_path = tempfile.mkdtemp()
- subprocess.set_conman_paths(conman_path, None)
- subprocess.mock('wifi', 'interfaces',
- subprocess.wifi.MockInterface(phynum='0', bands=['5'],
- driver='cfg80211'))
- subprocess.wifi.WPA_PATH = wpa_path
-
- w.attach_wpa_control(wpa_path)
- wvtest.WVFAIL(w.wpa_supplicant)
-
- # Set up.
- ssid = 'my=ssid'
- psk = 'passphrase'
- subprocess.mock('wifi', 'remote_ap', ssid=ssid, psk=psk, band='5',
- bssid='00:00:00:00:00:00', connection_check_result='succeed')
- subprocess.check_call(['wifi', 'setclient', '--ssid', ssid, '--band', '5'],
- env={'WIFI_CLIENT_PSK': psk})
-
- w.set_gateway_ip('192.168.1.1')
- w.set_subnet('192.168.1.0/24')
- wvtest.WVFAIL(w.wpa_supplicant)
- w.attach_wpa_control(wpa_path)
- w.handle_wpa_events()
-
- def check_working():
- w.update_routes(True)
- wvtest.WVPASS(w.wpa_supplicant)
- wvtest.WVPASS('default' in w.current_routes())
-
- def check_broken():
- w.update_routes(True)
- wvtest.WVFAIL(w.wpa_supplicant)
- wvtest.WVFAIL('default' in w.current_routes())
-
- check_working()
-
- # This is the buggy state.
- w.wpa_supplicant = False
- check_broken()
-
- # Should fix itself when we next run handle_wpa_events.
- w.handle_wpa_events()
- check_working()
-
- finally:
- shutil.rmtree(wpa_path)
- shutil.rmtree(conman_path)
-
-
if __name__ == '__main__':
wvtest.wvtest_main()
diff --git a/conman/iw_test.py b/conman/iw_test.py
index 202d10c..9f5f0e6 100755
--- a/conman/iw_test.py
+++ b/conman/iw_test.py
@@ -5,6 +5,7 @@
import subprocess
import iw
+import test_common
from wvtest import wvtest
@@ -34,7 +35,7 @@
)
-@wvtest.wvtest
+@test_common.wvtest
def find_bssids_test():
"""Test iw.find_bssids."""
subprocess.mock('wifi', 'interfaces',
diff --git a/conman/ratchet.py b/conman/ratchet.py
index 61e8705..8013c3d 100644
--- a/conman/ratchet.py
+++ b/conman/ratchet.py
@@ -16,11 +16,6 @@
_gettime = time.time
-# This has to be called before another module calls it with a higher log level.
-# pylint: disable=g-import-not-at-top
-logging.basicConfig(level=logging.DEBUG)
-
-
class TimeoutException(Exception):
pass
@@ -33,7 +28,7 @@
if evaluate:
self.evaluate = evaluate
self.timeout = timeout
- self.logger = logger or logging
+ self.logger = logger or logging.getLogger(self.name)
self.callback = callback
self.reset()
@@ -129,7 +124,7 @@
self.name = name
self.steps = steps
for step in self.steps:
- step.logger = logging.getLogger(self.name)
+ step.logger = logging.getLogger(self.name).getChild(step.name)
self._status = status
super(Ratchet, self).__init__(name, None, 0)
diff --git a/conman/ratchet_test.py b/conman/ratchet_test.py
index 48b693c..e0b831e 100755
--- a/conman/ratchet_test.py
+++ b/conman/ratchet_test.py
@@ -9,10 +9,11 @@
import ratchet
import status
+import test_common
from wvtest import wvtest
-@wvtest.wvtest
+@test_common.wvtest
def condition_test():
"""Test basic Condition functionality."""
x = y = 0
@@ -42,7 +43,7 @@
wvtest.WVPASSEQ(len(callback_sink), 2)
-@wvtest.wvtest
+@test_common.wvtest
def file_condition_test():
"""Test File*Condition functionality."""
_, filename = tempfile.mkstemp()
@@ -70,7 +71,7 @@
wvtest.WVFAIL(c_touched.check())
-@wvtest.wvtest
+@test_common.wvtest
def ratchet_test():
"""Test Ratchet functionality."""
@@ -88,7 +89,7 @@
ratchet.Condition('x', lambda: x, 0.1),
ratchet.Condition('y', lambda: y, 0.1),
ratchet.Condition('z', lambda: z, 0.1),
- ], status.Status(status_export_path))
+ ], status.Status('test ratchet', status_export_path))
x = y = 1
# Test that timeouts are not just summed, but start whenever the previous
diff --git a/conman/status.py b/conman/status.py
index c5d4187..0b6ac6a 100644
--- a/conman/status.py
+++ b/conman/status.py
@@ -30,7 +30,6 @@
COULD_REACH_ACS = 'COULD_REACH_ACS'
CAN_REACH_INTERNET = 'CAN_REACH_INTERNET'
PROVISIONING_FAILED = 'PROVISIONING_FAILED'
- ATTACHED_TO_WPA_SUPPLICANT = 'ATTACHED_TO_WPA_SUPPLICANT'
WAITING_FOR_PROVISIONING = 'WAITING_FOR_PROVISIONING'
WAITING_FOR_DHCP = 'WAITING_FOR_DHCP'
@@ -82,10 +81,6 @@
(P.HAVE_CONFIG,),
(),
),
- P.ATTACHED_TO_WPA_SUPPLICANT: (
- (),
- (),
- ),
P.WAITING_FOR_PROVISIONING: (
(P.CONNECTED_TO_OPEN,),
(),
@@ -137,6 +132,7 @@
"""
def __init__(self, *args, **kwargs):
+ self._scope = kwargs.pop('scope', '')
super(Proposition, self).__init__(*args, **kwargs)
self._value = None
self._implications = set()
@@ -180,7 +176,8 @@
self.export()
for parent in self.parents:
parent.export()
- logging.debug('%s is now %s', self._name, self._value)
+ logging.getLogger(self._scope).getChild(self._name).debug(
+ 'now %s', self._value)
if value:
for implication in self._implications:
@@ -214,7 +211,8 @@
class Status(object):
"""Provides a convenient API for conman to describe system status."""
- def __init__(self, export_path):
+ def __init__(self, name, export_path):
+ self._name = name
if not os.path.isdir(export_path):
os.makedirs(export_path)
@@ -224,7 +222,7 @@
def _set_up_propositions(self):
self._propositions = {
- p: Proposition(p, self._export_path)
+ p: Proposition(p, self._export_path, scope=self._name)
for p in dict(inspect.getmembers(P)) if not p.startswith('_')
}
@@ -260,9 +258,9 @@
class CompositeStatus(Status):
- def __init__(self, export_path, children):
+ def __init__(self, name, export_path, children):
self._children = children
- super(CompositeStatus, self).__init__(export_path)
+ super(CompositeStatus, self).__init__(name, export_path)
def _set_up_propositions(self):
self._propositions = {
diff --git a/conman/status_test.py b/conman/status_test.py
index 38dda83..6a591aa 100755
--- a/conman/status_test.py
+++ b/conman/status_test.py
@@ -2,16 +2,14 @@
"""Tests for connection_manager.py."""
-import logging
import os
import shutil
import tempfile
import status
+import test_common
from wvtest import wvtest
-logging.basicConfig(level=logging.DEBUG)
-
def file_in(path, filename):
return os.path.exists(os.path.join(path, filename))
@@ -21,7 +19,7 @@
return file_in(s._export_path, filename)
-@wvtest.wvtest
+@test_common.wvtest
def test_proposition():
export_path = tempfile.mkdtemp()
@@ -73,16 +71,16 @@
shutil.rmtree(export_path)
-@wvtest.wvtest
+@test_common.wvtest
def test_status():
export_path_s = tempfile.mkdtemp()
export_path_t = tempfile.mkdtemp()
export_path_st = tempfile.mkdtemp()
try:
- s = status.Status(export_path_s)
- t = status.Status(export_path_t)
- st = status.CompositeStatus(export_path_st, [s, t])
+ s = status.Status('s', export_path_s)
+ t = status.Status('t', export_path_t)
+ st = status.CompositeStatus('s_or t', export_path_st, [s, t])
# Sanity check that there are no contradictions.
for p, (want_true, want_false) in status.IMPLICATIONS.iteritems():
diff --git a/conman/test/fake_python/subprocess/ip.py b/conman/test/fake_python/subprocess/ip.py
index d8baaf3..9fcd5da 100644
--- a/conman/test/fake_python/subprocess/ip.py
+++ b/conman/test/fake_python/subprocess/ip.py
@@ -9,6 +9,8 @@
import ifup
+logger = logging.getLogger(__name__)
+
_ROUTING_TABLE = {}
_IP_TABLE = {}
@@ -74,17 +76,17 @@
if not can_add_route(dev):
return (1, 'Tried to add default route without subnet route: %r' %
_ROUTING_TABLE)
- logging.debug('Adding route for %r', key)
+ logger.debug('Adding route for %r', key)
_ROUTING_TABLE[key] = ' '.join(args[1:])
elif args[0] == 'del':
if key in _ROUTING_TABLE:
- logging.debug('Deleting route for %r', key)
+ logger.debug('Deleting route for %r', key)
del _ROUTING_TABLE[key]
elif key[2] is None:
# pylint: disable=g-builtin-op
for k in _ROUTING_TABLE.keys():
if k[:-1] == key[:-1]:
- logging.debug('Deleting route for %r (generalized from %s)', k, key)
+ logger.debug('Deleting route for %r (generalized from %s)', k, key)
del _ROUTING_TABLE[k]
break
diff --git a/conman/test/fake_python/subprocess/qcsapi.py b/conman/test/fake_python/subprocess/qcsapi.py
index 3625772..a7622a5 100644
--- a/conman/test/fake_python/subprocess/qcsapi.py
+++ b/conman/test/fake_python/subprocess/qcsapi.py
@@ -14,11 +14,9 @@
def mock(*args, **kwargs):
- import logging
if 'value' not in kwargs:
raise ValueError('Must specify value for mock qcsapi call %r' % args)
value = kwargs['value']
- logging.debug ('qcsapi %r mocked: %r', args, value)
if value is None and args in STATE:
del STATE[args]
else:
diff --git a/conman/test/fake_python/subprocess/wifi.py b/conman/test/fake_python/subprocess/wifi.py
index 13d1be3..900b908 100644
--- a/conman/test/fake_python/subprocess/wifi.py
+++ b/conman/test/fake_python/subprocess/wifi.py
@@ -67,8 +67,9 @@
class AccessPoint(object):
def __init__(self, **kwargs):
- for attr in ('ssid', 'psk', 'band', 'bssid', 'security', 'rssi',
- 'vendor_ies', 'connection_check_result', 'hidden'):
+ self._attrs = ('ssid', 'psk', 'band', 'bssid', 'security', 'rssi',
+ 'vendor_ies', 'connection_check_result', 'hidden')
+ for attr in self._attrs:
setattr(self, attr, kwargs.get(attr, None))
def scan_str(self):
@@ -86,6 +87,13 @@
rssi='%.2f dBm' % (self.rssi or 0),
security=security_strs.get(self.security, ''))
+ def __str__(self):
+ return 'AccessPoint<%s>' % ' '.join('%s=%s' % (attr, getattr(self, attr))
+ for attr in self._attrs)
+
+ def __repr__(self):
+ return str(self)
+
def call(*args, **kwargs):
wifi_commands = {
@@ -140,14 +148,14 @@
ap = REMOTE_ACCESS_POINTS[band].get(bssid, None)
if not ap or ap.ssid != ssid:
_setclient_error_not_found(interface_name, ssid, interface.driver)
- return 1, ('AP with band %r and BSSID %r and ssid %s not found'
- % (band, bssid, ssid))
+ return 1, ('AP with band %r and BSSID %r and ssid %s not found: %s'
+ % (band, bssid, ssid, REMOTE_ACCESS_POINTS))
elif ssid:
candidates = [ap for ap in REMOTE_ACCESS_POINTS[band].itervalues()
if ap.ssid == ssid]
if not candidates:
_setclient_error_not_found(interface_name, ssid, interface.driver)
- return 1, 'AP with SSID %r not found' % ssid
+ return 1, 'AP with SSID %r not found: %s' % (ssid, REMOTE_ACCESS_POINTS)
ap = random.choice(candidates)
else:
raise ValueError('Did not specify BSSID or SSID in %r' % args)
diff --git a/conman/test/fake_python/wpactrl.py b/conman/test/fake_python/wpactrl.py
deleted file mode 100644
index 3d8e300..0000000
--- a/conman/test/fake_python/wpactrl.py
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/usr/bin/python
-
-"""Fake WPACtrl implementation."""
-
-import os
-
-import subprocess
-import subprocess.wifi
-
-
-CONNECTED_EVENT = '<2>CTRL-EVENT-CONNECTED'
-DISCONNECTED_EVENT = '<2>CTRL-EVENT-DISCONNECTED'
-TERMINATING_EVENT = '<2>CTRL-EVENT-TERMINATING'
-
-
-# pylint: disable=invalid-name
-class error(Exception):
- pass
-
-
-class WPACtrl(object):
- """Fake wpactrl.WPACtrl."""
-
- # pylint: disable=unused-argument
- def __init__(self, wpa_socket):
- self._socket = wpa_socket
- self.interface_name = os.path.split(self._socket)[-1]
- self.attached = False
- self.connected = False
- self.request_status_fails = False
- self._clear_events()
-
- def pending(self):
- return bool(subprocess.wifi.INTERFACE_EVENTS[self.interface_name])
-
- def recv(self):
- return subprocess.wifi.INTERFACE_EVENTS[self.interface_name].pop(0)
-
- def attach(self):
- if not os.path.exists(self._socket):
- raise error('wpactrl_attach failed')
- self.attached = True
-
- def detach(self):
- self.attached = False
- self.connected = False
- self.check_socket_exists('wpactrl_detach failed')
- self._clear_events()
-
- def request(self, request_type):
- if request_type == 'STATUS':
- if self.request_status_fails:
- raise error('test error')
- try:
- return subprocess.check_output(['wpa_cli', '-i', self.interface_name,
- 'status'])
- except subprocess.CalledProcessError as e:
- raise error(e.output)
- else:
- raise ValueError('Invalid request_type %s' % request_type)
-
- @property
- def ctrl_iface_path(self):
- return os.path.split(self._socket)[0]
-
- # Below methods are not part of WPACtrl.
-
- def check_socket_exists(self, msg='Socket does not exist'):
- if not os.path.exists(self._socket):
- raise error(msg)
-
- def _clear_events(self):
- subprocess.wifi.INTERFACE_EVENTS[self.interface_name] = []
diff --git a/conman/test_common.py b/conman/test_common.py
new file mode 100644
index 0000000..202b712
--- /dev/null
+++ b/conman/test_common.py
@@ -0,0 +1,40 @@
+#!/usr/bin/python
+
+"""Configures generic stuff for unit tests."""
+
+
+import collections
+import logging
+
+from wvtest import wvtest as real_wvtest
+
+
+logging.basicConfig(level=logging.DEBUG)
+logger = logging.getLogger(__name__)
+
+
+class LoggerCounter(logging.Handler):
+ """Counts the number of messages from each logger."""
+
+ def __init__(self):
+ super(LoggerCounter, self).__init__()
+ self.counts = collections.defaultdict(int)
+
+ def handle(self, record):
+ self.counts[record.name] += 1
+
+
+def num_root_messages(logger_counter):
+ logging.getLogger(__name__).debug('logger counts: %s', logger_counter.counts)
+ return logger_counter.counts['root']
+
+
+def wvtest(f):
+ @real_wvtest.wvtest
+ def inner(*args, **kwargs):
+ logger_counter = LoggerCounter()
+ logging.getLogger().addHandler(logger_counter)
+ f(*args, **kwargs)
+ real_wvtest.WVPASSEQ(num_root_messages(logger_counter), 0)
+ inner.func_name = f.func_name
+ return inner
diff --git a/experiment.py b/experiment.py
index 7ec45ef..1318974 100644
--- a/experiment.py
+++ b/experiment.py
@@ -6,6 +6,7 @@
import os
import subprocess
+logger = logging.getLogger(__name__)
EXPERIMENTS_TMP_DIR = '/tmp/experiments'
EXPERIMENTS_DIR = '/config/experiments'
@@ -18,10 +19,10 @@
try:
rv = subprocess.call(['register_experiment', name])
except OSError as e:
- logging.info('register_experiment: %s', e)
+ logger.info('register_experiment: %s', e)
else:
if rv:
- logging.error('Failed to register experiment %s.', name)
+ logger.error('Failed to register experiment %s.', name)
def enabled(name):
@@ -39,14 +40,14 @@
name + '.available')):
if name not in _experiment_warned:
_experiment_warned.add(name)
- logging.warning('Warning: experiment %r not registered.', name)
+ logger.warning('Warning: experiment %r not registered.', name)
else:
is_enabled = os.path.exists(os.path.join(EXPERIMENTS_DIR,
name + '.active'))
if is_enabled and name not in _experiment_enabled:
_experiment_enabled.add(name)
- logging.info('Notice: using experiment %r.', name)
+ logger.info('Notice: using experiment %r.', name)
elif not is_enabled and name in _experiment_enabled:
_experiment_enabled.remove(name)
- logging.info('Notice: stopping experiment %r.', name)
+ logger.info('Notice: stopping experiment %r.', name)
return is_enabled
diff --git a/experiment_testutils.py b/experiment_testutils.py
index f5886e5..3561ca3 100644
--- a/experiment_testutils.py
+++ b/experiment_testutils.py
@@ -9,12 +9,14 @@
import experiment
+logger = logging.getLogger(__name__)
+
def enable(name):
"""Enable an experiment. For unit tests only."""
open(os.path.join(experiment.EXPERIMENTS_TMP_DIR, name + '.available'), 'w')
open(os.path.join(experiment.EXPERIMENTS_DIR, name + '.active'), 'w')
- logging.debug('Enabled %s for unit tests', name)
+ logger.debug('Enabled %s for unit tests', name)
def disable(name):
@@ -22,7 +24,7 @@
filename = os.path.join(experiment.EXPERIMENTS_DIR, name + '.active')
if os.path.exists(filename):
os.unlink(filename)
- logging.debug('Disabled %s for unit tests', name)
+ logger.debug('Disabled %s for unit tests', name)
class MakeExperimentDirs(object):
diff --git a/ginstall/ginstall.py b/ginstall/ginstall.py
index 1ec1729..affd475 100755
--- a/ginstall/ginstall.py
+++ b/ginstall/ginstall.py
@@ -1239,7 +1239,7 @@
# handle 'ginstall -p <partition>' separately
if not opt.drm and not opt.tar:
- partition = GetPartition(opt, GetOs())
+ partition = GetPartition(opt.partition, GetOs())
if SetBootPartition(GetOs(), partition) != 0:
VerbosePrint('Unable to set boot partition\n')
return HNVRAM_ERR
diff --git a/gpio-mailbox/Makefile b/gpio-mailbox/Makefile
index b73d99f..f6cb77f 100644
--- a/gpio-mailbox/Makefile
+++ b/gpio-mailbox/Makefile
@@ -29,6 +29,8 @@
CFLAGS += -DGFIBER_LT
else ifeq ($(BR2_TARGET_GENERIC_PLATFORM_NAME),gflt200)
CFLAGS += -DGFIBER_LT
+else ifeq ($(BR2_TARGET_GENERIC_PLATFORM_NAME),gflt400)
+ CFLAGS += -DGFIBER_LT
else ifeq ($(BR2_TARGET_GENERIC_PLATFORM_NAME),gfmn100)
CFLAGS += -DWINDCHARGER
else ifeq ($(BR2_TARGET_GENERIC_PLATFORM_NAME),gfch100)
diff --git a/hnvram/Makefile b/hnvram/Makefile
index 2790f4d..badf27a 100644
--- a/hnvram/Makefile
+++ b/hnvram/Makefile
@@ -11,7 +11,7 @@
BINDIR=$(DESTDIR)$(PREFIX)/bin
HUMAX_UPGRADE_DIR ?= ../../../humax/misc/libupgrade
-CFLAGS += -g -Os -I$(HUMAX_UPGRADE_DIR) $(EXTRACFLAGS)
+CFLAGS += -g -Os -I$(HUMAX_UPGRADE_DIR) -I$(HUMAX_UPGRADE_DIR)/test $(EXTRACFLAGS)
LDFLAGS += -L$(HUMAX_UPGRADE_DIR) $(EXTRALDFLAGS)
all: hnvram
@@ -22,12 +22,16 @@
$(CC) $(CFLAGS) $(SRCS) -o $@ $(LDFLAGS) -lhmxupgrade
unit_test: test
-test: hnvram_test
- ./hnvram_test
+test: clean hnvram_unit_test hnvram_integration_test
+ ./hnvram_unit_test
+ ./hnvram_integration_test
-hnvram_test: hnvram_test.cc hnvram_main.c $(INCS)
+hnvram_unit_test: hnvram_test.cc hnvram_main.c $(INCS)
$(CPP) $(CFLAGS) hnvram_test.cc -o $@ $(LDFLAGS) -lgtest -lpthread
+hnvram_integration_test: hnvram_integration_test.cc
+ $(CPP) $(CFLAGS) hnvram_integration_test.cc -o $@ $(LDFLAGS) -lgtest -lpthread
+
install:
mkdir -p $(BINDIR)
cp hnvram $(BINDIR)/hnvram_binary
@@ -36,4 +40,4 @@
@echo "No libs to install."
clean:
- rm -f hnvram hnvram_test *.o
+ rm -f hnvram hnvram_unit_test hnvram_integration_test *.o
diff --git a/hnvram/hnvram_integration_test.cc b/hnvram/hnvram_integration_test.cc
new file mode 100644
index 0000000..b7ceda1
--- /dev/null
+++ b/hnvram/hnvram_integration_test.cc
@@ -0,0 +1,205 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+// Author: germuth@google.com (Aaron Germuth)
+
+// Tests external methods of hnvram_main end-to-end. No stubbing of lower-level
+// methods (Black box testing)
+
+#include <stdio.h>
+#include "gtest/gtest.h"
+#include "hmx_upgrade_nvram.h"
+
+#define TEST_MAIN
+#include "hnvram_main.c"
+#include "hmx_test_base.cc"
+#include "hmx_upgrade_nvram.c"
+#include "hmx_upgrade_flash.c"
+
+// Test constants
+const char* name = "NEW_VAR";
+const char* val = "ABCDEF";
+const char* val2 = "ZZZZZZZZZ";
+const int valLen = 6;
+const int valLen2 = 9;
+
+const char* fieldName = "MAC_ADDR_BT";
+const char* fieldVal = "\x01\x02\x03\x04\x05\x06";
+const char* fieldValStr = "01:02:03:04:05:06";
+const char* fieldVal2 = "12:34:56:78:0a:bc";
+const int fieldValLen = 6;
+
+// Test parameters
+const HMX_NVRAM_PARTITION_E partitions[] =
+ {HMX_NVRAM_PARTITION_RO, HMX_NVRAM_PARTITION_RW};
+HMX_NVRAM_PARTITION_E part;
+
+class HnvramIntegrationTest : public HnvramTest,
+ public ::testing::WithParamInterface<HMX_NVRAM_PARTITION_E> {
+ public:
+ HnvramIntegrationTest() {}
+ virtual ~HnvramIntegrationTest() {}
+
+ virtual void SetUp() {
+ part = GetParam();
+
+ libupgrade_verbose = 0;
+ can_add_flag = 0;
+
+ HnvramTest::SetUp();
+
+ HMX_NVRAM_Init(hnvramFileName);
+ }
+
+ virtual void TearDown() {
+ part = HMX_NVRAM_PARTITION_UNSPECIFIED;
+
+ // clear dlists
+ drv_NVRAM_Delete(HMX_NVRAM_PARTITION_RO, (unsigned char*)fieldName);
+ drv_NVRAM_Delete(HMX_NVRAM_PARTITION_RW, (unsigned char*)name);
+ drv_NVRAM_Delete(HMX_NVRAM_PARTITION_RO, (unsigned char*)name);
+
+ HnvramTest::TearDown();
+ }
+};
+
+TEST_P(HnvramIntegrationTest, TestWriteNvramNew) {
+ // Should fail without can_add
+ EXPECT_EQ(-1, write_nvram_new(name, val, part));
+
+ // Should fail to parse
+ can_add_flag = 1;
+ char valLarge[NVRAM_MAX_DATA + 1];
+ memset(valLarge, 1, sizeof(valLarge));
+ EXPECT_EQ(-2, write_nvram_new(name, valLarge, part));
+
+ // Should fail cleanly with bad partition
+ HMX_NVRAM_Init("/tmp/");
+ EXPECT_EQ(-3, write_nvram_new(name, val, part));
+
+ // Read back writes
+ HMX_NVRAM_Init(hnvramFileName);
+ unsigned char read[255];
+ unsigned int readLen = 0;
+ EXPECT_EQ(0, write_nvram_new(name, val, part));
+ EXPECT_EQ(DRV_OK,
+ HMX_NVRAM_Read(part, (unsigned char*)name, 0,
+ read, sizeof(read), &readLen));
+ EXPECT_EQ(0, memcmp(val, read, valLen));
+ EXPECT_EQ(valLen, readLen);
+}
+
+TEST_P(HnvramIntegrationTest, TestWriteNvram) {
+ // Should fail with large val
+ char valLarge[NVRAM_MAX_DATA + 1];
+ memset(valLarge, 1, sizeof(valLarge));
+ EXPECT_EQ(-1, write_nvram(name, valLarge, part));
+
+ // Failure to parse
+ EXPECT_EQ(-2, write_nvram(fieldName, "not-proper-mac-addr", part));
+
+ // Variable doesn't already exist
+ EXPECT_EQ(-3, write_nvram(name, val, part));
+
+ // Variable exists in wrong partition
+ can_add_flag = 1;
+ EXPECT_EQ(0, write_nvram_new(name, val, part));
+ EXPECT_EQ(-4, write_nvram(name, val, HMX_NVRAM_PARTITION_W_RAWFS));
+
+ // Fail cleanly from lower-level write
+ HMX_NVRAM_Init("/tmp/");
+ EXPECT_EQ(-5, write_nvram(name, val, part));
+ HMX_NVRAM_Init(hnvramFileName);
+
+ // Try to specify partition with a field variable
+ EXPECT_EQ(0, write_nvram_new(fieldName, fieldVal, part));
+ HMX_NVRAM_Init(hnvramFileName);
+ EXPECT_EQ(-6, write_nvram(fieldName, fieldVal2, part));
+
+ // Failure from lower-level write w/field
+ HMX_NVRAM_Init("/tmp/");
+ char out[255];
+ EXPECT_EQ(-7, write_nvram(fieldName, fieldValStr,
+ HMX_NVRAM_PARTITION_UNSPECIFIED));
+ HMX_NVRAM_Init(hnvramFileName);
+
+ // Read back val after changing val
+ EXPECT_EQ(0, write_nvram(name, val2, part));
+ unsigned char read[255];
+ unsigned int readLen = 0;
+ EXPECT_EQ(DRV_OK, HMX_NVRAM_Read(part, (unsigned char*)name, 0,
+ read, sizeof(read), &readLen));
+ EXPECT_EQ(0, memcmp(read, val2, readLen));
+ EXPECT_EQ(readLen, valLen2);
+}
+
+TEST_P(HnvramIntegrationTest, TestClearNvram) {
+ // Delete non-existing variable
+ HMX_NVRAM_Init(hnvramFileName);
+ EXPECT_EQ(DRV_OK, clear_nvram(name));
+
+ can_add_flag = 1;
+ EXPECT_EQ(0, write_nvram_new(name, val, part));
+
+ // No hnvram partition
+ HMX_NVRAM_Init("/tmp/");
+ EXPECT_EQ(DRV_ERR, clear_nvram(name));
+
+ // Delete Existing
+ HMX_NVRAM_Init(hnvramFileName);
+ EXPECT_EQ(DRV_OK, clear_nvram(name));
+}
+
+TEST_P(HnvramIntegrationTest, TestReadNvram) {
+ char readR[255];
+ memset(readR, 56, 30);
+ HMX_NVRAM_PARTITION_E part_used;
+ EXPECT_TRUE(NULL == read_nvram(fieldName, readR, sizeof(readR), 0, &part_used));
+
+ // No variable to find
+ EXPECT_EQ(NULL, read_nvram(name, readR, sizeof(readR), 0, &part_used));
+
+ // Find field
+ can_add_flag = 1;
+ EXPECT_EQ(0, write_nvram_new(fieldName, fieldVal, HMX_NVRAM_PARTITION_RO));
+ EXPECT_FALSE(NULL == read_nvram(fieldName, readR, sizeof(readR), 1, &part_used));
+ EXPECT_EQ(0, memcmp(readR, fieldValStr, 18));
+ EXPECT_EQ(part_used, HMX_NVRAM_PARTITION_RO);
+
+ // Find variable
+ EXPECT_EQ(0, write_nvram_new(name, val, part));
+ EXPECT_FALSE(NULL == read_nvram(name, readR, sizeof(readR), 1, &part_used));
+ EXPECT_EQ(0, memcmp(readR, val, valLen));
+ EXPECT_EQ(part_used, part);
+}
+
+TEST_P(HnvramIntegrationTest, TestInitNvram) {
+ char readR[255];
+ HMX_NVRAM_PARTITION_E part_used;
+
+ // Set envvar to bad file
+ EXPECT_EQ(0, setenv("HNVRAM_LOCATION", "/tmp/", 1));
+ EXPECT_EQ(DRV_OK, init_nvram());
+
+ // Should fail to read
+ EXPECT_TRUE(NULL == read_nvram(name, readR, sizeof(readR), 1, &part_used));
+
+ // Set envvar to proper, empty file
+ EXPECT_EQ(0, setenv("HNVRAM_LOCATION", hnvramFileName, 1));
+ EXPECT_EQ(DRV_OK, init_nvram());
+
+ // Write and read it back
+ can_add_flag = 1;
+ EXPECT_EQ(0, write_nvram_new(name, val, part));
+
+ EXPECT_FALSE(NULL == read_nvram(name, readR, sizeof(readR), 1, &part_used));
+ EXPECT_EQ(0, memcmp(readR, val, valLen));
+ EXPECT_EQ(part_used, part);
+}
+
+INSTANTIATE_TEST_CASE_P(TryAllPartitions, HnvramIntegrationTest,
+ ::testing::ValuesIn(partitions));
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ::testing::AddGlobalTestEnvironment(new HnvramEnvironment);
+ return RUN_ALL_TESTS();
+}
diff --git a/hnvram/hnvram_main.c b/hnvram/hnvram_main.c
index a406caa..e1dd780 100644
--- a/hnvram/hnvram_main.c
+++ b/hnvram/hnvram_main.c
@@ -42,6 +42,8 @@
printf("\t-n : toggles whether -w can create new variables. Default is off\n");
printf("\t-p [RW|RO] : toggles what partition new writes (-n) used. Default is RW\n");
printf("\t-k VARNAME : delete existing key/value pair from NVRAM.\n");
+ printf("\t Set environment variable: $HNVRAM_LOCATION to change where read/writes are performed.");
+ printf("\t By default hnvram uses '/dev/mtd/hnvram'\n");
}
// Format of data in the NVRAM
@@ -369,7 +371,7 @@
return NULL;
}
-DRV_Error clear_nvram(char* optarg) {
+DRV_Error clear_nvram(const char* optarg) {
DRV_Error err1 = HMX_NVRAM_Remove(HMX_NVRAM_PARTITION_RW,
(unsigned char*)optarg);
DRV_Error err2 = HMX_NVRAM_Remove(HMX_NVRAM_PARTITION_RO,
@@ -387,7 +389,8 @@
}
-int write_nvram(char* name, char* value, HMX_NVRAM_PARTITION_E desired_part) {
+int write_nvram(const char* name, const char* value,
+ HMX_NVRAM_PARTITION_E desired_part) {
const hnvram_field_t* field = get_nvram_field(name);
int is_field = (field != NULL);
@@ -400,8 +403,8 @@
if (strlen(value) > NVRAM_MAX_DATA) {
fprintf(stderr, "Value length %d exceeds maximum data size of %d\n",
- strlen(value), NVRAM_MAX_DATA);
- return -2;
+ (int)strlen(value), NVRAM_MAX_DATA);
+ return -1;
}
unsigned char nvram_value[NVRAM_MAX_DATA];
@@ -444,18 +447,18 @@
}
// Adds new variable to HNVRAM in desired_partition as STRING
-int write_nvram_new(char* name, char* value,
+int write_nvram_new(const char* name, const char* value,
HMX_NVRAM_PARTITION_E desired_part) {
+ if (!can_add_flag) {
+ fprintf(stderr, "Key not found in NVRAM. Add -n to allow creation %s\n",
+ name);
+ return -1;
+ }
+
char tmp[NVRAM_MAX_DATA] = {0};
unsigned char nvram_value[NVRAM_MAX_DATA];
unsigned int nvram_len = sizeof(nvram_value);
if (parse_nvram(HNVRAM_STRING, value, nvram_value, &nvram_len) == NULL) {
- return -1;
- }
-
- if (!can_add_flag) {
- fprintf(stderr, "Key not found in NVRAM. Add -n to allow creation %s\n",
- name);
return -2;
}
@@ -472,13 +475,19 @@
return 0;
}
+int init_nvram() {
+ const char* location = getenv("HNVRAM_LOCATION");
+ return (int)HMX_NVRAM_Init(location);
+}
+
int hnvram_main(int argc, char* const argv[]) {
DRV_Error err;
libupgrade_verbose = 0;
- if ((err = HMX_NVRAM_Init()) != DRV_OK) {
- fprintf(stderr, "NVRAM Init failed: %d\n", err);
+ int ret = init_nvram();
+ if (ret != 0) {
+ fprintf(stderr, "NVRAM Init failed: %d\n", ret);
exit(1);
}
@@ -524,13 +533,13 @@
char* value = equal + 1;
int ret = write_nvram(name, value, desired_part);
- if (ret == -3 && can_add_flag) {
- // key not found, and we are authorized to add a new one
+ if (ret == -3) {
+ // key not found, try to add a new one
ret = write_nvram_new(name, value, desired_part);
}
if (ret != 0) {
- fprintf(stderr, "Unable to write %s\n", duparg);
+ fprintf(stderr, "Err %d: Unable to write %s\n", ret, duparg);
free(duparg);
exit(1);
}
diff --git a/hnvram/hnvram_test.cc b/hnvram/hnvram_test.cc
index 643a436..dbc05a1 100644
--- a/hnvram/hnvram_test.cc
+++ b/hnvram/hnvram_test.cc
@@ -85,7 +85,7 @@
return HMX_NVRAM_SetField_Return;
}
-DRV_Error HMX_NVRAM_Init(void) {
+DRV_Error HMX_NVRAM_Init(const char* target_mtd) {
return DRV_OK;
}
diff --git a/taxonomy/wifi.py b/taxonomy/wifi.py
index 3b497e2..b2a0086 100644
--- a/taxonomy/wifi.py
+++ b/taxonomy/wifi.py
@@ -779,6 +779,8 @@
('Nexus 6', '', '2.4GHz'),
'wifi4|probe:0,1,50,3,45,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:002d,htagg:17,htmcs:0000ffff,wps:Nexus_6|assoc:0,1,50,33,36,48,45,221(001018,2),221(0050f2,2),htcap:002d,htagg:17,htmcs:0000ffff,txpow:1209':
('Nexus 6', '', '2.4GHz'),
+ 'wifi4|probe:0,1,50,3,45,127,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:002d,htagg:17,htmcs:0000ffff,extcap:000008800140,wps:Nexus_6|assoc:0,1,50,33,36,48,45,127,221(001018,2),221(0050f2,2),htcap:002d,htagg:17,htmcs:0000ffff,txpow:140b,extcap:000008800140':
+ ('Nexus 6', '', '2.4GHz'),
'wifi4|probe:0,1,45,191,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,wps:Nexus_6P|assoc:0,1,33,36,48,45,191,221(001018,2),221(0050f2,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,txpow:e002':
('Nexus 6P', '', '5GHz'),
@@ -786,6 +788,12 @@
('Nexus 6P', '', '5GHz'),
'wifi4|probe:0,1,50,3,45,127,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:002d,htagg:17,htmcs:0000ffff,extcap:0000088001400040,wps:Nexus_6P|assoc:0,1,50,33,36,48,45,127,221(001018,2),221(0050f2,2),htcap:002d,htagg:17,htmcs:0000ffff,txpow:1402,extcap:0000088001400040':
('Nexus 6P', '', '2.4GHz'),
+ 'wifi4|probe:0,1,50,3,45,127,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:002d,htagg:17,htmcs:0000ffff,extcap:0000088001400040,wps:Nexus_6P|assoc:0,1,50,33,36,48,45,127,221(001018,2),221(0050f2,2),htcap:002d,htagg:17,htmcs:0000ffff,txpow:1302,extcap:0000088001400040':
+ ('Nexus 6P', '', '2.4GHz'),
+ 'wifi4|probe:0,1,50,3,45,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:002d,htagg:17,htmcs:0000ffff,wps:Nexus_6P|assoc:0,1,50,33,36,48,45,221(001018,2),221(0050f2,2),htcap:002d,htagg:17,htmcs:0000ffff,txpow:1302':
+ ('Nexus 6P', '', '2.4GHz'),
+ 'wifi4|probe:0,1,50,3,45,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:002d,htagg:17,htmcs:0000ffff,wps:Nexus_6P|assoc:0,1,50,33,36,48,45,221(001018,2),221(0050f2,2),htcap:002d,htagg:17,htmcs:0000ffff,txpow:1402':
+ ('Nexus 6P', '', '2.4GHz'),
'wifi4|probe:0,1,50,45,3,221(001018,2),221(00904c,51),htcap:110c,htagg:19,htmcs:000000ff|assoc:0,1,48,50,45,221(001018,2),221(00904c,51),221(0050f2,2),htcap:110c,htagg:19,htmcs:000000ff|oui:asus':
('Nexus 7', '2012 edition', '2.4GHz'),
@@ -816,6 +824,8 @@
('Nexus 7', '2013 edition', '5GHz'),
'wifi4|probe:0,1,45,htcap:016e,htagg:03,htmcs:000000ff|assoc:0,1,33,36,48,45,221(0050f2,2),127,htcap:016e,htagg:03,htmcs:000000ff,txpow:1e0d,extcap:00000a02|oui:asus':
('Nexus 7', '2013 edition', '5GHz'),
+ 'wifi4|probe:0,1,45,221(0050f2,8),127,221(0050f2,4),221(506f9a,10),221(506f9a,9),htcap:016e,htagg:03,htmcs:000000ff,extcap:00000a02,wps:Nexus_7|assoc:0,1,48,45,221(0050f2,2),127,htcap:016e,htagg:03,htmcs:000000ff,extcap:00000a02':
+ ('Nexus 7', '2013 edition', '5GHz'),
'wifi4|probe:0,1,50,45,221(0050f2,8),127,221(0050f2,4),221(506f9a,9),htcap:012c,htagg:03,htmcs:000000ff,extcap:00000a02,wps:Nexus_7|assoc:0,1,50,48,45,221(0050f2,2),127,htcap:012c,htagg:03,htmcs:000000ff,extcap:00000a02':
('Nexus 7', '2013 edition', '2.4GHz'),
'wifi4|probe:0,1,50,45,221(0050f2,8),221(0050f2,4),221(506f9a,9),htcap:012c,htagg:03,htmcs:000000ff,wps:Nexus_7|assoc:0,1,50,48,45,221(0050f2,2),127,htcap:012c,htagg:03,htmcs:000000ff,extcap:00000a02':
@@ -828,11 +838,19 @@
('Nexus 7', '2013 edition', '2.4GHz'),
'wifi4|probe:0,1,50,45,221(0050f2,8),221(0050f2,4),221(506f9a,9),htcap:012c,htagg:03,htmcs:000000ff,wps:Nexus_7|assoc:0,1,50,48,45,221(0050f2,2),htcap:012c,htagg:03,htmcs:000000ff':
('Nexus 7', '2013 edition', '2.4GHz'),
+ 'wifi4|probe:0,1,50,45,221(0050f2,8),127,221(0050f2,4),221(506f9a,10),221(506f9a,9),htcap:012c,htagg:03,htmcs:000000ff,extcap:00000a02,wps:Nexus_7|assoc:0,1,50,48,45,221(0050f2,2),127,htcap:012c,htagg:03,htmcs:000000ff,extcap:00000a02':
+ ('Nexus 7', '2013 edition', '2.4GHz'),
+ 'wifi4|probe:0,1,50,3,45,221(0050f2,8),127,221(0050f2,4),221(506f9a,9),htcap:012c,htagg:03,htmcs:000000ff,extcap:00000a02,wps:Nexus_7|assoc:0,1,50,48,45,221(0050f2,2),127,htcap:012c,htagg:03,htmcs:000000ff,extcap:00000a02':
+ ('Nexus 7', '2013 edition', '2.4GHz'),
'wifi4|probe:0,1,45,127,191,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,extcap:000008800140,wps:Nexus_9|assoc:0,1,33,36,48,45,127,191,221(001018,2),221(0050f2,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,txpow:e009,extcap:000008800140':
('Nexus 9', '', '5GHz'),
'wifi4|probe:0,1,45,191,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,wps:Nexus_9|assoc:0,1,33,36,48,45,191,221(001018,2),221(0050f2,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,txpow:e009':
('Nexus 9', '', '5GHz'),
+ 'wifi4|probe:0,1,45,127,191,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,extcap:0000088001400040,wps:Nexus_9|assoc:0,1,33,36,48,45,127,191,221(001018,2),221(0050f2,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,txpow:e009,extcap:0000088001400040':
+ ('Nexus 9', '', '5GHz'),
+ 'wifi4|probe:0,1,45,127,191,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,extcap:000008800140,wps:Nexus_9|assoc:0,1,33,36,48,45,127,191,221(001018,2),221(0050f2,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,txpow:e20b,extcap:000008800140':
+ ('Nexus 9', '', '5GHz'),
'wifi4|probe:0,1,50,3,45,127,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:002d,htagg:17,htmcs:0000ffff,extcap:0000088001400040,wps:Nexus_9|assoc:0,1,50,33,36,48,45,127,221(001018,2),221(0050f2,2),htcap:002d,htagg:17,htmcs:0000ffff,txpow:1309,extcap:000008800140':
('Nexus 9', '', '2.4GHz'),
'wifi4|probe:0,1,50,3,45,127,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:002d,htagg:17,htmcs:0000ffff,extcap:000008800140,wps:Nexus_9|assoc:0,1,50,33,36,48,45,127,221(001018,2),221(0050f2,2),htcap:002d,htagg:17,htmcs:0000ffff,txpow:150b,extcap:000008800140':
@@ -849,6 +867,8 @@
'wifi4|probe:0,1,45,127,191,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,extcap:0000088001400040,wps:Nexus_Player|assoc:0,1,33,36,48,45,127,191,221(001018,2),221(0050f2,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,txpow:e009,extcap:0000088001400040':
('Nexus Player', '', '5GHz'),
+ 'wifi4|probe:0,1,45,127,191,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,extcap:000008800140,wps:Nexus_Player|assoc:0,1,33,36,48,45,127,191,221(001018,2),221(0050f2,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,txpow:e009,extcap:000008800140':
+ ('Nexus Player', '', '5GHz'),
'wifi4|probe:0,1,50,3,45,127,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:002d,htagg:17,htmcs:0000ffff,extcap:000008800140,wps:Nexus_Player|assoc:0,1,50,33,36,48,45,127,221(001018,2),221(0050f2,2),htcap:002d,htagg:17,htmcs:0000ffff,txpow:1209,extcap:000008800140':
('Nexus Player', '', '2.4GHz'),
'wifi4|probe:0,1,50,3,45,127,221(0050f2,4),221(506f9a,9),221(001018,2),htcap:002d,htagg:17,htmcs:0000ffff,extcap:0000088001400040,wps:Nexus_Player|assoc:0,1,50,33,36,48,45,127,221(001018,2),221(0050f2,2),htcap:002d,htagg:17,htmcs:0000ffff,txpow:1209,extcap:000008800140':
diff --git a/wifi/configs.py b/wifi/configs.py
index a4f20b8..572b1c9 100644
--- a/wifi/configs.py
+++ b/wifi/configs.py
@@ -370,14 +370,15 @@
else:
network_block_lines = wpa_network_lines(ssid, passphrase)
+ freq_list = ' '.join(autochannel.get_all_frequencies(opt.band))
+
network_block_lines.append('\tscan_ssid=1')
if opt.bssid:
network_block_lines.append('\tbssid=%s' %
utils.validate_and_sanitize_bssid(opt.bssid))
+ network_block_lines.append('\tfreq_list=' + freq_list)
network_block = make_network_block(network_block_lines)
- freq_list = ' '.join(autochannel.get_all_frequencies(opt.band))
-
lines = [
'ctrl_interface=/var/run/wpa_supplicant',
'ap_scan=1',
diff --git a/wifi/configs_test.py b/wifi/configs_test.py
index 016fc27..bd28626 100755
--- a/wifi/configs_test.py
+++ b/wifi/configs_test.py
@@ -26,6 +26,7 @@
\t#psk="some passphrase"
\tpsk=41821f7ca3ea5d85beea7644ed7e0fefebd654177fa06c26fbdfdc3c599a317f
\tscan_ssid=1
+\tfreq_list={freq_list}
}}
"""
@@ -39,6 +40,7 @@
\tpsk=41821f7ca3ea5d85beea7644ed7e0fefebd654177fa06c26fbdfdc3c599a317f
\tscan_ssid=1
\tbssid=12:34:56:78:90:ab
+\tfreq_list={freq_list}
}}
"""
@@ -53,6 +55,7 @@
\tkey_mgmt=NONE
\tscan_ssid=1
\tbssid=12:34:56:78:90:ab
+\tfreq_list={freq_list}
}}
"""
diff --git a/wifi/qca9880_cal.py b/wifi/qca9880_cal.py
index 4e5cc0c..7c18454 100755
--- a/wifi/qca9880_cal.py
+++ b/wifi/qca9880_cal.py
@@ -9,10 +9,11 @@
import glob
import os
import os.path
+import struct
import experiment
import utils
-NO_CAL_EXPERIMENT = 'WifiNoCalibrationPatch'
+CAL_EXPERIMENT = 'WifiCalibrationPatch'
PLATFORM_FILE = '/etc/platform'
CALIBRATION_DIR = '/tmp/ath10k_cal'
CAL_PATCH_FILE = 'cal_data_patch.bin'
@@ -23,9 +24,32 @@
VERSION_LEN = 3
SUSPECT_OUIS = ((0x28, 0x24, 0xff), (0x48, 0xa9, 0xd2), (0x60, 0x02, 0xb4),
(0xbc, 0x30, 0x7d), (0xbc, 0x30, 0x7e))
-MISCALIBRATED_VERSION_FIELD = (0x0, 0x0, 0x0)
MODULE_PATH = '/sys/class/net/{}/device/driver/module'
+# Each tuple starts with an offset, followed by a list of values to be
+# patched beginning at that offset.
+CAL_PATCH = ((0x050a, (0x5c, 0x68, 0xbd, 0xcd)),
+ (0x0510, (0x5c, 0x68, 0xbd, 0xcd)),
+ (0x0516, (0x5c, 0x68, 0xbd, 0xcd)),
+ (0x051c, (0x5c, 0x68, 0xbd, 0xcd)),
+ (0x0531, (0x2a, 0x28, 0x26)),
+ (0x0535, (0x2a, 0x28, 0x26)),
+ (0x056b, (0xce, 0x8a, 0x66, 0x02, 0x68, 0x26, 0x80, 0x66)),
+ (0x05b4, (0x8a, 0x46, 0x02, 0x68, 0x24, 0x80, 0x46)),
+ (0x05c0, (0x8a, 0x46, 0x02, 0x68, 0x24, 0x80, 0x46)),
+ (0x05fc, (0x8c, 0x68, 0x02, 0x88, 0x26, 0x80)),
+ (0x0608, (0x8c, 0x68, 0x02, 0x88, 0x26, 0x80)))
+
+FCC_PATCH = ((0x0625, (0x50, 0x58, 0x5c, 0x8c, 0xbd, 0xc1, 0xcd,
+ 0x4c, 0x50, 0x58, 0x5c, 0x8c, 0xbd, 0xc1,
+ 0xcd, 0x4e, 0x56, 0x5e, 0x66, 0x8e)),
+ (0x06b4, (0x69, 0x6b, 0x6b, 0x62, 0x62, 0x6b, 0x6c,
+ 0x2d, 0x69, 0x6b, 0x6b, 0x62, 0x62, 0x6b,
+ 0x6d, 0x2d, 0x62, 0x6f, 0x68, 0x64, 0x64,
+ 0x68, 0x68, 0x2d, 0x5c, 0x60, 0x60, 0x66)))
+
+experiment.register(CAL_EXPERIMENT)
+
def _log(msg):
utils.log('ath10k calibration: {}'.format(msg))
@@ -75,14 +99,23 @@
"""Check the QCA8990 module to see if it is improperly calibrated.
There are two manufacturers of the modules, Senao and Wistron of which only
- Wistron modules are suspect. Wistron provided a list of OUIs manufactured
- which are listed in SUSPECT_OUIS. Modules manufactured by Winstron containing
- V02 at offset VERSION_OFFSET have been corrected, while those containing 3
- zero's at this offset are still suspect and will be considered mis-calibrated.
+ Wistron modules are suspect. Wistron provided a list of suspect OUIs
+ which are listed in SUSPECT_OUIS.
+
+ The version field must also be checked, starting at offset VERSION_OFFSET.
+ If this fields is all zeros, then it is an implicit indication of V01,
+ otherwise it contains a version string.
+
+ V01 -- (version field contains 0's) These modules need both calibration and
+ FCC power limits patched.
+ V02 -- Only FCC power limits need to be patched
+ V03 -- No patching required.
Returns:
- True if module is mis-calibrated, None if it can't be determined, and False
- otherwise.
+ A tuple containing one or both of: fcc, cal. Or None.
+ 'fcc' -- FCC patching required.
+ 'cal' -- Calibration data patching required.
+ None -- No patching required.
"""
try:
@@ -94,7 +127,7 @@
f.seek(OUI_OFFSET)
oui = f.read(OUI_LEN)
f.seek(VERSION_OFFSET)
- version = f.read(VERSION_LEN)
+ version = struct.unpack('3s', f.read(VERSION_LEN))[0]
except IOError as e:
_log('unable to open cal_data {}: {}'.format(cal_data_path, e.strerror))
@@ -102,17 +135,27 @@
if oui not in (bytearray(s) for s in SUSPECT_OUIS):
_log('OUI {} is properly calibrated.'.format(_oui_string(oui)))
- return False
+ # Create an empty directory so this script short-circuits if run again.
+ _create_calibration_dir()
+ return None
- if version != (bytearray(MISCALIBRATED_VERSION_FIELD)):
- _log('version field {} signals proper calibration.'.
- format(_version_string(version)))
- return False
+ # V01 is retroactively represented not by a string, but by 3 0 value bytes.
+ if version == '\x00\x00\x00':
+ _log('version field is V01. CAL + FCC calibration required.')
+ return ('fcc', 'cal')
- _log('May be mis-calibrated. OUI: {} version: {}'.
- format(_oui_string(oui), _version_string(version)))
+ if version == 'V02':
+ _log('version field is V02. Only FCC calibration required.')
+ return ('fcc',)
- return True
+ if version == 'V03':
+ _log('version field is V03. No patching required.')
+ # Create an empty directory so this script short-circuits if run again.
+ _create_calibration_dir()
+ return None
+
+ _log('version field unknown: {}'.format(version))
+ return None
def _is_previously_calibrated():
@@ -160,9 +203,18 @@
return glob.glob(ATH10K_CAL_DATA)[0]
-def _generate_calibration_patch():
+def _apply_patch(msg, cal_data, patch):
+ _log(msg)
+ for offset, values in patch:
+ cal_data[offset:offset + len(values)] = values
+
+
+def _generate_calibration_patch(calibration_state):
"""Create calibration patch and write to storage.
+ Args:
+ calibration_state: data from ath10k to be patched.
+
Returns:
True for success or False for failure.
"""
@@ -174,11 +226,12 @@
format(_ath10k_cal_data_path(), e.strerror))
return False
- # Patch cal_data here once we get the actual calibration data.
- # For now just return False until we get the data.
- _log('patch not generated as data not supplied yet.')
- # pylint: disable=unreachable
- return False
+ # Actual calibration starts here.
+ if 'cal' in calibration_state:
+ _apply_patch('Applying CAL patch...', cal_data, CAL_PATCH)
+
+ if 'fcc' in calibration_state:
+ _apply_patch('Applying FCC patch...', cal_data, FCC_PATCH)
if not _create_calibration_dir():
return False
@@ -211,8 +264,9 @@
def qca8990_calibration():
"""Main QCA8990 calibration check."""
- if experiment.enabled(NO_CAL_EXPERIMENT):
- _log('experiment {} on. Skip calibration check.'.format(NO_CAL_EXPERIMENT))
+ if not experiment.enabled(CAL_EXPERIMENT):
+ _log('experiment {} not specified. Skipping calibration check.'.
+ format(CAL_EXPERIMENT))
return
if _is_previously_calibrated():
@@ -223,15 +277,9 @@
_log('this platform does not use ath10k.')
return
- cal_result = _is_module_miscalibrated()
- if cal_result is None:
- _log('unknown if miscalibrated.')
- elif not cal_result:
- _log('module is NOT miscalibrated.')
- # Creating an empty directory signals that this script has already run.
- _create_calibration_dir()
- else:
- if _generate_calibration_patch():
+ calibration_state = _is_module_miscalibrated()
+ if calibration_state is not None:
+ if _generate_calibration_patch(calibration_state):
_log('generated new patch.')
_reload_driver()
diff --git a/wifi/quantenna.py b/wifi/quantenna.py
index bb541f5..9e0d26b 100755
--- a/wifi/quantenna.py
+++ b/wifi/quantenna.py
@@ -11,7 +11,7 @@
def _get_quantenna_interfaces():
- return subprocess.check_output(['get-quantenna-interfaces']).split()
+ return utils.read_or_empty('/sys/class/net/quantenna/vlan')
def _qcsapi(*args):
@@ -27,13 +27,6 @@
return ':'.join(octets)
-def _get_vlan(hif):
- m = re.search(r'VID: (\d+)', utils.read_or_empty('/proc/net/vlan/%s' % hif))
- if m:
- return int(m.group(1))
- raise utils.BinWifiException('no VLAN ID for interface %s' % hif)
-
-
def _get_interfaces(mode, suffix):
# Each host interface (hif) maps to exactly one LHOST interface (lif) based on
# the VLAN ID as follows: the lif is wifiX where X is the VLAN ID - 2 (VLAN
@@ -41,11 +34,12 @@
# VLAN ID 2.
prefix = 'wlan' if mode == 'ap' else 'wcli'
suffix = r'.*' if suffix == 'ALL' else suffix
- for hif in _get_quantenna_interfaces():
+ for line in _get_quantenna_interfaces().splitlines():
+ hif, vlan = line.split()
+ vlan = int(vlan)
+ lif = 'wifi%d' % (vlan - 2)
+ mac = _get_external_mac(hif)
if re.match(r'^' + prefix + r'\d*' + suffix + r'$', hif):
- vlan = _get_vlan(hif)
- lif = 'wifi%d' % (vlan - 2)
- mac = _get_external_mac(hif)
yield hif, lif, mac, vlan
@@ -64,8 +58,11 @@
def _parse_scan_result(line):
# Scan result format:
#
- # "Quantenna1" 00:26:86:00:11:5f 60 56 1 2 1 2 0 15 80
- # | | | | | | | | | | |
+ # "Quantenna1" 00:26:86:00:11:5f 60 56 1 2 1 2 0 15 80 100 1 Infrastructure
+ # | | | | | | | | | | | | | |
+ # | | | | | | | | | | | | | Mode
+ # | | | | | | | | | | | | DTIM interval
+ # | | | | | | | | | | | Beacon interval
# | | | | | | | | | | Maximum bandwidth
# | | | | | | | | | WPS flags
# | | | | | | | | Qhop flags
@@ -80,7 +77,7 @@
#
# The SSID may contain quotes and spaces. Split on whitespace from the right,
# making at most 10 splits, to preserve spaces in the SSID.
- sp = line.strip().rsplit(None, 10)
+ sp = line.strip().rsplit(None, 13)
return sp[0][1:-1], sp[1], int(sp[2]), -float(sp[3]), int(sp[4]), int(sp[5])
diff --git a/wifi/quantenna_test.py b/wifi/quantenna_test.py
index b0fb485..00400ed 100755
--- a/wifi/quantenna_test.py
+++ b/wifi/quantenna_test.py
@@ -16,37 +16,25 @@
@wvtest.wvtest
-def get_vlan_test():
- old_read_or_empty = utils.read_or_empty
- utils.read_or_empty = lambda _: 'wlan0 VID: 3 REORDER_HDR: 1'
- wvtest.WVPASSEQ(quantenna._get_vlan('wlan0'), 3)
- utils.read_or_empty = lambda _: ''
- wvtest.WVEXCEPT(utils.BinWifiException, quantenna._get_vlan, 'wlan0')
- utils.read_or_empty = old_read_or_empty
-
-
-@wvtest.wvtest
def get_interface_test():
old_get_quantenna_interfaces = quantenna._get_quantenna_interfaces
old_get_external_mac = quantenna._get_external_mac
- old_get_vlan = quantenna._get_vlan
- quantenna._get_quantenna_interfaces = lambda: ['wlan0', 'wlan0_portal']
+ quantenna._get_quantenna_interfaces = lambda: 'wlan0 3\nwlan0_portal 4\n'
quantenna._get_external_mac = lambda _: '00:00:00:00:00:00'
- quantenna._get_vlan = lambda _: 3
wvtest.WVPASSEQ(quantenna._get_interface('ap', ''),
('wlan0', 'wifi1', '00:00:00:00:00:00', 3))
wvtest.WVPASSEQ(quantenna._get_interface('ap', '_portal'),
- ('wlan0_portal', 'wifi1', '00:00:00:00:00:00', 3))
+ ('wlan0_portal', 'wifi2', '00:00:00:00:00:00', 4))
wvtest.WVPASSEQ(quantenna._get_interface('sta', ''),
(None, None, None, None))
- quantenna._get_vlan = old_get_vlan
quantenna._get_external_mac = old_get_external_mac
quantenna._get_quantenna_interfaces = old_get_quantenna_interfaces
@wvtest.wvtest
def parse_scan_result_test():
- result = ' " ssid with "quotes" " 00:11:22:33:44:55 40 25 0 0 0 0 0 1 40 '
+ result = (' " ssid with "quotes" " 00:11:22:33:44:55 40 25 0 0 0 0 0 1 40 '
+ '100 1 Infrastructure')
wvtest.WVPASSEQ(quantenna._parse_scan_result(result),
(' ssid with "quotes" ', '00:11:22:33:44:55', 40, -25, 0, 0))