Merge "Refactor isoping and add unit tests."
diff --git a/hnvram/hnvram_main.c b/hnvram/hnvram_main.c
index 1148bb0..a406caa 100644
--- a/hnvram/hnvram_main.c
+++ b/hnvram/hnvram_main.c
@@ -14,7 +14,7 @@
#include "hmx_upgrade_nvram.h"
// Max length of data in an NVRAM field
-#define NVRAM_MAX_DATA 4096
+#define NVRAM_MAX_DATA (64*1024)
// Number of bytes of GPN to be represented as hex data
#define GPN_HEX_BYTES 4
@@ -33,13 +33,14 @@
}
void usage(const char* progname) {
- printf("Usage: %s [-d | [-q|-b] [-r|-k] VARNAME] [ [-n] -w VARNAME=value]\n", progname);
+ printf("Usage: %s [-d | [-q|-b] [-r|-k] VARNAME] [ [-n [-p [RO|RW]]] -w VARNAME=value]\n", progname);
printf("\t-d : dump all NVRAM variables\n");
printf("\t-r VARNAME : read VARNAME from NVRAM\n");
printf("\t-q : quiet mode, suppress the variable name and equal sign\n");
printf("\t-b : read VARNAME from NVRAM in raw binary format, e.g. dumping a binary key\n");
printf("\t-w VARNAME=value : write value to VARNAME in NVRAM.\n");
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");
}
@@ -190,7 +191,14 @@
return (int)ret;
}
-char* read_nvram(const char* name, char* output, int outlen, int quiet) {
+// name - name of key to be read
+// output - buffer for value of key
+// outlen - length of buffer
+// quiet - whether buffer is KEY=VAL or VAL
+// part_used - in the case of dynamically added variables (is_field = false),
+// returns what partition we found the key in
+char* read_nvram(const char* name, char* output, int outlen, int quiet,
+ HMX_NVRAM_PARTITION_E* part_used) {
const hnvram_field_t* field = get_nvram_field(name);
int is_field = (field != NULL);
@@ -205,10 +213,18 @@
}
} else {
format_type = HNVRAM_STRING;
- DRV_Error e = HMX_NVRAM_Read(HMX_NVRAM_PARTITION_RW, (unsigned char*)name,
- 0, data, sizeof(data), &data_len);
+
+ // Try both partitions
+ *part_used = HMX_NVRAM_PARTITION_RW;
+ DRV_Error e = HMX_NVRAM_Read(*part_used, (unsigned char*)name, 0, data,
+ sizeof(data), &data_len);
if (e != DRV_OK) {
- return NULL;
+ *part_used = HMX_NVRAM_PARTITION_RO;
+ e = HMX_NVRAM_Read(*part_used, (unsigned char*)name, 0, data,
+ sizeof(data), &data_len);
+ if (e != DRV_OK) {
+ return NULL;
+ }
}
}
char formatbuf[NVRAM_MAX_DATA * 2];
@@ -228,7 +244,8 @@
unsigned char* output, unsigned int* outlen) {
int len = strlen(input);
if (len > *outlen) {
- len = *outlen;
+ // Data is too large, don't permit a partial write.
+ return NULL;
}
strncpy((char*)output, input, len);
@@ -353,25 +370,24 @@
}
DRV_Error clear_nvram(char* optarg) {
- DRV_Error e = HMX_NVRAM_Remove(HMX_NVRAM_PARTITION_RW,
- (unsigned char*)optarg);
- if (e == DRV_ERR) {
- // Avoid throwing error message if variable already cleared
+ DRV_Error err1 = HMX_NVRAM_Remove(HMX_NVRAM_PARTITION_RW,
+ (unsigned char*)optarg);
+ DRV_Error err2 = HMX_NVRAM_Remove(HMX_NVRAM_PARTITION_RO,
+ (unsigned char*)optarg);
+
+ // Avoid throwing error message if variable already cleared
+ if ((err1 == DRV_ERR || err1 == DRV_OK) &&
+ (err2 == DRV_ERR || err2 == DRV_OK)) {
return DRV_OK;
}
- return e;
+
+ fprintf(stderr, "Error while deleting key %s. RW: %d RO: %d.\n", optarg,
+ err1, err2);
+ return DRV_ERR;
}
-int write_nvram(char* optarg) {
- char* equal = strchr(optarg, '=');
- if (equal == NULL) {
- return -1;
- }
- char* name = optarg;
- *equal = '\0';
- char* value = ++equal;
-
+int write_nvram(char* name, char* value, HMX_NVRAM_PARTITION_E desired_part) {
const hnvram_field_t* field = get_nvram_field(name);
int is_field = (field != NULL);
@@ -382,6 +398,12 @@
format_type = HNVRAM_STRING;
}
+ 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;
+ }
+
unsigned char nvram_value[NVRAM_MAX_DATA];
unsigned int nvram_len = sizeof(nvram_value);
if (parse_nvram(format_type, value, nvram_value, &nvram_len) == NULL) {
@@ -390,22 +412,61 @@
if (!is_field) {
char tmp[NVRAM_MAX_DATA] = {0};
- int key_exists = (read_nvram(name, tmp, NVRAM_MAX_DATA, 1) != NULL);
- if (!can_add_flag && !key_exists) {
- fprintf(stderr, "Key not found in NVRAM. Add -n to allow creation %s\n",
- name);
- return -3;
+ HMX_NVRAM_PARTITION_E part_used;
+ if (read_nvram(name, tmp, NVRAM_MAX_DATA, 1, &part_used) == NULL) {
+ return -3; // Write failed: Variable not found
}
- DRV_Error er = HMX_NVRAM_Write(HMX_NVRAM_PARTITION_RW, (unsigned char*)name,
- 0, nvram_value, nvram_len);
- if (er != DRV_OK) {
+
+ if (desired_part != HMX_NVRAM_PARTITION_UNSPECIFIED &&
+ desired_part != part_used) {
+ fprintf(stderr, "Variable already exists in other partition: %s\n", name);
return -4;
}
- } else {
- if (HMX_NVRAM_SetField(field->nvram_type, 0,
- nvram_value, nvram_len) != DRV_OK) {
+
+ DRV_Error er = HMX_NVRAM_Write(part_used, (unsigned char*)name, 0,
+ nvram_value, nvram_len);
+ if (er != DRV_OK) {
return -5;
}
+ } else {
+ if (desired_part != HMX_NVRAM_PARTITION_UNSPECIFIED) {
+ fprintf(stderr, "Partition was specified (%d) on a field variable: %s\n",
+ desired_part, name);
+ return -6;
+ }
+ if (HMX_NVRAM_SetField(field->nvram_type, 0,
+ nvram_value, nvram_len) != DRV_OK) {
+ return -7;
+ }
+ }
+
+ return 0;
+}
+
+// Adds new variable to HNVRAM in desired_partition as STRING
+int write_nvram_new(char* name, char* value,
+ HMX_NVRAM_PARTITION_E desired_part) {
+ 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;
+ }
+
+ if (desired_part == HMX_NVRAM_PARTITION_UNSPECIFIED) {
+ desired_part = HMX_NVRAM_PARTITION_RW;
+ }
+
+ DRV_Error er = HMX_NVRAM_Write(desired_part, (unsigned char*)name, 0,
+ nvram_value, nvram_len);
+ if (er != DRV_OK) {
+ return -3;
}
return 0;
@@ -425,9 +486,11 @@
int op_cnt = 0; // operation
int q_flag = 0; // quiet: don't output name of variable.
int b_flag = 0; // binary: output the binary format
+ // Desired partition for new writes.
+ HMX_NVRAM_PARTITION_E desired_part = HMX_NVRAM_PARTITION_UNSPECIFIED;
char output[NVRAM_MAX_DATA];
int c;
- while ((c = getopt(argc, argv, "dbqrnw:k:")) != -1) {
+ while ((c = getopt(argc, argv, "dbqrnp:w:k:")) != -1) {
switch(c) {
case 'b':
b_flag = 1;
@@ -438,10 +501,35 @@
case 'n':
can_add_flag = 1;
break;
+ case 'p':
+ if (strcmp(optarg, "RO") == 0) {
+ desired_part = HMX_NVRAM_PARTITION_RO;
+ } else if (strcmp(optarg, "RW") == 0) {
+ desired_part = HMX_NVRAM_PARTITION_RW;
+ } else {
+ fprintf(stderr, "Invalid partition: %s. Use RW or RO\n", optarg);
+ exit(1);
+ }
+ break;
case 'w':
{
char* duparg = strdup(optarg);
- if (write_nvram(duparg) != 0) {
+ char* equal = strchr(duparg, '=');
+ if (equal == NULL) {
+ return -1;
+ }
+
+ char* name = duparg;
+ *equal = '\0';
+ 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
+ ret = write_nvram_new(name, value, desired_part);
+ }
+
+ if (ret != 0) {
fprintf(stderr, "Unable to write %s\n", duparg);
free(duparg);
exit(1);
@@ -503,7 +591,8 @@
}
fwrite(output, 1, len, stdout);
} else {
- if (read_nvram(argv[optind], output, sizeof(output), q_flag) == NULL) {
+ HMX_NVRAM_PARTITION_E part_used;
+ if (read_nvram(argv[optind], output, sizeof(output), q_flag, &part_used) == NULL) {
fprintf(stderr, "Unable to read %s\n", argv[optind]);
exit(1);
}
diff --git a/hnvram/hnvram_test.cc b/hnvram/hnvram_test.cc
index 39f7e4a..643a436 100644
--- a/hnvram/hnvram_test.cc
+++ b/hnvram/hnvram_test.cc
@@ -8,16 +8,31 @@
int libupgrade_verbose = 1;
-char* HMX_NVRAM_Read_Data = NULL;
+char* HMX_NVRAM_Read_Data_RO = NULL;
+char* HMX_NVRAM_Read_Data_RW = NULL;
+
+char* get_Read_Data(HMX_NVRAM_PARTITION_E partition) {
+ if (partition == HMX_NVRAM_PARTITION_RO) {
+ return HMX_NVRAM_Read_Data_RO;
+ } else {
+ return HMX_NVRAM_Read_Data_RW;
+ }
+}
+
DRV_Error HMX_NVRAM_Read(HMX_NVRAM_PARTITION_E partition,
unsigned char* pName, unsigned int offset,
unsigned char* pValue, unsigned int ulSize,
unsigned int* pLen) {
- if (HMX_NVRAM_Read_Data == NULL) {
+ if (get_Read_Data(partition) == NULL) {
return DRV_ERR;
+ }
+ if (partition == HMX_NVRAM_PARTITION_RO) {
+ snprintf((char*)pValue, ulSize, "%s", HMX_NVRAM_Read_Data_RO);
+ *pLen = strlen(HMX_NVRAM_Read_Data_RO);
+ return DRV_OK;
} else {
- snprintf((char*)pValue, ulSize, "%s", HMX_NVRAM_Read_Data);
- *pLen = strlen(HMX_NVRAM_Read_Data);
+ snprintf((char*)pValue, ulSize, "%s", HMX_NVRAM_Read_Data_RW);
+ *pLen = strlen(HMX_NVRAM_Read_Data_RW);
return DRV_OK;
}
}
@@ -25,17 +40,26 @@
DRV_Error HMX_NVRAM_Write(HMX_NVRAM_PARTITION_E partition,
unsigned char* pName, unsigned int offset,
unsigned char* pValue, unsigned int ulSize) {
- HMX_NVRAM_Read_Data = (char*)malloc(ulSize);
- snprintf(HMX_NVRAM_Read_Data, sizeof(pValue), "%s", (char*)pValue);
+ if (partition == HMX_NVRAM_PARTITION_RO) {
+ HMX_NVRAM_Read_Data_RO = (char*)malloc(ulSize);
+ snprintf(HMX_NVRAM_Read_Data_RO, sizeof(pValue), "%s", (char*)pValue);
+ } else {
+ HMX_NVRAM_Read_Data_RW = (char*)malloc(ulSize);
+ snprintf(HMX_NVRAM_Read_Data_RW, sizeof(pValue), "%s", (char*)pValue);
+ }
return DRV_OK;
}
DRV_Error HMX_NVRAM_Remove(HMX_NVRAM_PARTITION_E partition,
unsigned char* pName) {
- if (HMX_NVRAM_Read_Data == NULL) {
+ if (get_Read_Data(partition) == NULL) {
return DRV_ERR;
}
- HMX_NVRAM_Read_Data = NULL;
+ if (partition == HMX_NVRAM_PARTITION_RO) {
+ HMX_NVRAM_Read_Data_RO = NULL;
+ } else {
+ HMX_NVRAM_Read_Data_RW = NULL;
+ }
return DRV_OK;
}
@@ -84,7 +108,8 @@
virtual ~HnvramTest() {}
virtual void SetUp() {
- HMX_NVRAM_Read_Data = NULL;
+ HMX_NVRAM_Read_Data_RO = NULL;
+ HMX_NVRAM_Read_Data_RW = NULL;
HMX_NVRAM_GetField_Data = NULL;
HMX_NVRAM_SetField_Data = NULL;
HMX_NVRAM_SetField_Len = -1;
@@ -184,104 +209,145 @@
TEST_F(HnvramTest, TestReadFieldNvram) {
char output[256];
+ HMX_NVRAM_PARTITION_E part;
HMX_NVRAM_GetField_Data = "TestSystemId";
EXPECT_STREQ("SYSTEM_ID=TestSystemId",
- read_nvram("SYSTEM_ID", output, sizeof(output), 0));
+ read_nvram("SYSTEM_ID", output, sizeof(output), 0, &part));
EXPECT_STREQ("TestSystemId",
- read_nvram("SYSTEM_ID", output, sizeof(output), 1));
+ read_nvram("SYSTEM_ID", output, sizeof(output), 1, &part));
HMX_NVRAM_GetField_Data = NULL;
- EXPECT_EQ(NULL, read_nvram("FAKE_SYSTEM_ID", output, sizeof(output), 1));
+ EXPECT_EQ(NULL, read_nvram("FAKE_SYSTEM_ID", output, sizeof(output), 1,
+ &part));
}
TEST_F(HnvramTest, TestReadVariableNvram) {
char output[256];
- HMX_NVRAM_Read_Data = strdup("ABC123");
+ HMX_NVRAM_PARTITION_E part;
+ HMX_NVRAM_Read_Data_RW = strdup("ABC123");
EXPECT_STREQ("TEST_VARIABLE=ABC123",
- read_nvram("TEST_VARIABLE", output, sizeof(output), 0));
+ read_nvram("TEST_VARIABLE", output, sizeof(output), 0, &part));
+ EXPECT_EQ((int)HMX_NVRAM_PARTITION_RW, part);
EXPECT_STREQ("ABC123",
- read_nvram("TEST_VARIABLE", output, sizeof(output), 1));
- HMX_NVRAM_Read_Data = NULL;
- EXPECT_STREQ(NULL, read_nvram("TEST_VARIABLE", output, sizeof(output), 1));
+ read_nvram("TEST_VARIABLE", output, sizeof(output), 1, &part));
+ EXPECT_EQ((int)HMX_NVRAM_PARTITION_RW, part);
+ HMX_NVRAM_Read_Data_RW = NULL;
+ EXPECT_STREQ(NULL, read_nvram("TEST_VARIABLE", output, sizeof(output), 1,
+ &part));
}
TEST_F(HnvramTest, TestWriteFieldNvram) {
// Type integer
- char* testdata = strdup("ACTIVATED_KERNEL_NUM=1");
- EXPECT_EQ(DRV_OK, write_nvram(testdata));
+ char* key = strdup("ACTIVATED_KERNEL_NUM");
+ char* val = strdup("1");
+ EXPECT_EQ(DRV_OK, write_nvram(key, val, HMX_NVRAM_PARTITION_UNSPECIFIED));
EXPECT_EQ(0x01, *HMX_NVRAM_SetField_Data);
EXPECT_EQ(1, HMX_NVRAM_SetField_Len);
// Type string
- testdata = strdup("ACTIVATED_KERNEL_NAME=kernel1");
- EXPECT_EQ(DRV_OK, write_nvram(testdata));
+ key = strdup("ACTIVATED_KERNEL_NAME");
+ val = strdup("kernel1");
+ EXPECT_EQ(DRV_OK, write_nvram(key, val, HMX_NVRAM_PARTITION_UNSPECIFIED));
EXPECT_STREQ("kernel1", (char*)HMX_NVRAM_SetField_Data);
EXPECT_EQ(7, HMX_NVRAM_SetField_Len);
// Make sure it called SetField and not HMX_NVRAM_Write
- EXPECT_EQ (NULL, HMX_NVRAM_Read_Data);
+ EXPECT_EQ (NULL, HMX_NVRAM_Read_Data_RW);
+ EXPECT_EQ (NULL, HMX_NVRAM_Read_Data_RO);
// Should fail trying to change value of non-exsting field
- testdata = strdup("FAKE_FIELD=abc123");
- EXPECT_NE(0, write_nvram(testdata));
- free(testdata);
+ key = strdup("FAKE_FIELD");
+ val = strdup("abc123");
+ EXPECT_NE(0, write_nvram(key, val, HMX_NVRAM_PARTITION_UNSPECIFIED));
+ free(key);
+ free(val);
}
-TEST_F(HnvramTest, TestWriteVariableNvram) {
+void testWriteVariableNvram(HMX_NVRAM_PARTITION_E partition, HMX_NVRAM_PARTITION_E other) {
char* key = strdup("TEST_FIELD");
char* val = strdup("abc123");
- char* keyval = strdup("TEST_FIELD=abc123");
// Fail to add new one without -n
- EXPECT_NE(0, write_nvram(strdup(keyval)));
+ EXPECT_NE(0, write_nvram(key, val, HMX_NVRAM_PARTITION_UNSPECIFIED));
+ EXPECT_NE(0, write_nvram(key, val, HMX_NVRAM_PARTITION_RW));
+ EXPECT_NE(0, write_nvram(key, val, HMX_NVRAM_PARTITION_RO));
- // Add new one successfully
can_add_flag = 1;
- EXPECT_EQ(0, write_nvram(keyval));
- EXPECT_STREQ(val,HMX_NVRAM_Read_Data);
+ EXPECT_EQ(-3, write_nvram(key, val, HMX_NVRAM_PARTITION_UNSPECIFIED));
+ EXPECT_EQ(-3, write_nvram(key, val, HMX_NVRAM_PARTITION_RO));
+ EXPECT_EQ(-3, write_nvram(key, val, HMX_NVRAM_PARTITION_RW));
+ // Add new one successfully
+ EXPECT_EQ(0, write_nvram_new(key, val, partition));
+ EXPECT_STREQ(val, get_Read_Data(partition));
// Should be able to read value
char output[256];
- EXPECT_STREQ(val, read_nvram(key, output, sizeof(output), 1));
+ HMX_NVRAM_PARTITION_E part_used;
+ EXPECT_STREQ(val, read_nvram(key, output, sizeof(output), 1, &part_used));
+
+ // Make sure read came from right partition
+ EXPECT_EQ(partition, part_used);
char* val2 = strdup("987def");
- char* keyval2 = strdup("TEST_FIELD=987def");
// Should be able to change value
- EXPECT_EQ(0, write_nvram(keyval2));
- EXPECT_STREQ(val2,HMX_NVRAM_Read_Data);
+ EXPECT_EQ(0, write_nvram(key, val2, HMX_NVRAM_PARTITION_UNSPECIFIED));
+ EXPECT_STREQ(val2, get_Read_Data(partition));
+
+ // And back again, this time with correct partition specified
+ EXPECT_EQ(0, write_nvram(key, val, partition));
+ EXPECT_STREQ(val, get_Read_Data(partition));
+
+ // Should fail when specifying wrong partition
+ EXPECT_EQ(-4, write_nvram(key, val2, other));
+ EXPECT_EQ(-4, write_nvram(key, val2, HMX_NVRAM_PARTITION_W_RAWFS));
free(key);
free(val);
- free(keyval);
free(val2);
- free(keyval2);
}
-TEST_F(HnvramTest, TestClearNvram) {
+TEST_F(HnvramTest, TestWriteVariableNvramRO) {
+ testWriteVariableNvram(HMX_NVRAM_PARTITION_RO, HMX_NVRAM_PARTITION_RW);
+}
+
+TEST_F(HnvramTest, TestWriteVariableNvramRW) {
+ testWriteVariableNvram(HMX_NVRAM_PARTITION_RW, HMX_NVRAM_PARTITION_RO);
+}
+
+void testClearNvram(HMX_NVRAM_PARTITION_E partition) {
char* key = strdup("TEST_FIELD2");
char* val = strdup("abc123");
- char* keyval = strdup("TEST_FIELD2=abc123");
// No error if variable already cleared
EXPECT_EQ(DRV_OK, clear_nvram(key));
- // Create new one
+ // Create new var
can_add_flag = 1;
- EXPECT_EQ(0, write_nvram(keyval));
- EXPECT_STREQ(val, HMX_NVRAM_Read_Data);
+ EXPECT_EQ(-3, write_nvram(key, val, HMX_NVRAM_PARTITION_UNSPECIFIED));
+ EXPECT_EQ(0, write_nvram_new(key, val, partition));
+ EXPECT_STREQ(val, get_Read_Data(partition));
// Should be able to read value
char output[256];
- EXPECT_STREQ(val, read_nvram(key, output, sizeof(output), 1));
+ HMX_NVRAM_PARTITION_E part_used;
+ EXPECT_STREQ(val, read_nvram(key, output, sizeof(output), 1, &part_used));
+ EXPECT_EQ((int)partition, part_used);
// Should be able to kill it
EXPECT_EQ(DRV_OK, clear_nvram(key));
// Should fail reading value
- EXPECT_STREQ(NULL, read_nvram(key, output, sizeof(output), 1));
+ EXPECT_STREQ(NULL, read_nvram(key, output, sizeof(output), 1, &part_used));
free(key);
free(val);
- free(keyval);
+}
+
+TEST_F(HnvramTest, TestClearNvramRO) {
+ testClearNvram(HMX_NVRAM_PARTITION_RO);
+}
+
+TEST_F(HnvramTest, TestClearNvramRW) {
+ testClearNvram(HMX_NVRAM_PARTITION_RW);
}
int main(int argc, char** argv) {
diff --git a/rcu_audio/ti-rcu-audio.cc b/rcu_audio/ti-rcu-audio.cc
index 67dd869..e174477 100644
--- a/rcu_audio/ti-rcu-audio.cc
+++ b/rcu_audio/ti-rcu-audio.cc
@@ -44,7 +44,11 @@
uint8 prev = 0;
int msgs = 0, missed = 0, errors = 0;
- is = get_socket_or_die();
+ if ((is = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
+ perror("socket(AF_UNIX)");
+ exit(1);
+ }
+
memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_UNIX;
snprintf(sun.sun_path, sizeof(sun.sun_path), "%s", TI_AUDIO_PATH);
diff --git a/taxonomy/pcaptest.py b/taxonomy/pcaptest.py
index 02c2039..3e2ea1f 100644
--- a/taxonomy/pcaptest.py
+++ b/taxonomy/pcaptest.py
@@ -19,6 +19,8 @@
('', './testdata/pcaps/HTC Sensation 2.4GHz.pcap'),
('', './testdata/pcaps/HTC Thunderbolt 2.4GHz.pcap'),
('', './testdata/pcaps/HTC Titan 2.4GHz.pcap'),
+ ('', './testdata/pcaps/iPad Mini 4th gen 5GHz MK6L2LL Broadcast Probe.pcap'),
+ ('', './testdata/pcaps/iPad Mini 4th gen 5GHz MK6L2LL Specific Probe.pcap'),
('', './testdata/pcaps/Lenovo_T440_80211ac_2x2_Windows8_2_4_GHz.pcap'),
('', './testdata/pcaps/LG E900 2.4GHz.pcap'),
('', './testdata/pcaps/LG G2X 2.4GHz.pcap'),
@@ -81,6 +83,8 @@
('Nest Thermostat v1 or v2', './testdata/pcaps/Nest Thermostat 2.4GHz.pcap'),
('Roku 2 or 3 or Streaming Stick', './testdata/pcaps/Roku 3 2.4GHz 4230.pcap'),
('Roku 2 or 3 or Streaming Stick', './testdata/pcaps/Roku 3 5GHz 4230.pcap'),
+ ('Roku 4 or TV', './testdata/pcaps/Roku 4 2.4GHz.pcap'),
+ ('Roku 4 or TV', './testdata/pcaps/Roku 4 5GHz.pcap'),
('Samsung Galaxy Note or S2+', './testdata/pcaps/Samsung Galaxy S2+ 5GHz.pcap'),
('Samsung Galaxy Note or S2+', './testdata/pcaps/Samsung Galaxy Note 5GHz.pcap'),
('Samsung Galaxy S2 or Infuse', './testdata/pcaps/Samsung Galaxy S2 2.4GHz.pcap'),
diff --git a/taxonomy/testdata/dhcp.leases b/taxonomy/testdata/dhcp.leases
index f3eae5e..51d4538 100644
--- a/taxonomy/testdata/dhcp.leases
+++ b/taxonomy/testdata/dhcp.leases
@@ -70,3 +70,6 @@
1432237016 70:48:0f:00:00:00 192.168.42.59 iPadPro12_9
1432237016 6c:c2:17:00:00:00 192.168.42.60 HPPrinter
1432237016 dc:2b:2a:95:bc:77 192.168.42.61 iPhoone 6s+
+1432237016 2c:33:61:00:00:00 192.168.42.62 iPhoone 7
+1432237016 58:bd:a3:00:00:00 192.168.42.63 Wii
+1432237016 28:0d:fc:00:00:00 192.168.42.64 Playstation 3
diff --git a/taxonomy/testdata/dhcp.signatures b/taxonomy/testdata/dhcp.signatures
index 0c79a18..614f33d 100644
--- a/taxonomy/testdata/dhcp.signatures
+++ b/taxonomy/testdata/dhcp.signatures
@@ -62,3 +62,6 @@
70:48:0f:00:00:00 1,3,6,15,119,252
6c:c2:17:00:00:00 6,3,1,15,66,67,13,44,12,81,252
dc:2b:2a:95:bc:77 1,3,6,15,119,252
+2c:33:61:00:00:00 1,3,6,15,119,252
+58:bd:a3:00:00:00 1,3,6,15,28,33
+28:0d:fc:00:00:00 1,3,15,6
diff --git a/taxonomy/testdata/pcaps/Playstation 3 2.4GHz Specific Probe.pcap b/taxonomy/testdata/pcaps/Playstation 3 2.4GHz Specific Probe.pcap
new file mode 100644
index 0000000..020011f
--- /dev/null
+++ b/taxonomy/testdata/pcaps/Playstation 3 2.4GHz Specific Probe.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/Wii 2.4GHz Broadcast Probe.pcap b/taxonomy/testdata/pcaps/Wii 2.4GHz Broadcast Probe.pcap
new file mode 100644
index 0000000..3b86e87
--- /dev/null
+++ b/taxonomy/testdata/pcaps/Wii 2.4GHz Broadcast Probe.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/Wii 2.4GHz Specific Probe.pcap b/taxonomy/testdata/pcaps/Wii 2.4GHz Specific Probe.pcap
new file mode 100644
index 0000000..4f7292a
--- /dev/null
+++ b/taxonomy/testdata/pcaps/Wii 2.4GHz Specific Probe.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/iPhone 7 5GHz.pcap b/taxonomy/testdata/pcaps/iPhone 7 5GHz.pcap
new file mode 100644
index 0000000..f910dc3
--- /dev/null
+++ b/taxonomy/testdata/pcaps/iPhone 7 5GHz.pcap
Binary files differ
diff --git a/taxonomy/wifi.py b/taxonomy/wifi.py
index 6b48061..36c92fc 100644
--- a/taxonomy/wifi.py
+++ b/taxonomy/wifi.py
@@ -355,9 +355,9 @@
'wifi4|probe:0,1,50,3,45,127,107,221(001018,2),221(00904c,51),221(0050f2,8),htcap:01bc,htagg:1b,htmcs:0000ffff,extcap:00000804|assoc:0,1,33,36,48,50,45,70,221(001018,2),221(00904c,51),221(0050f2,2),htcap:01bc,htagg:1b,htmcs:0000ffff,txpow:1201|os:ios':
('iPad Mini', '3rd gen', '2.4GHz'),
- 'wifi4|probe:0,1,45,127,107,191,221(0050f2,8),221(001018,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,extcap:0400088400000040|assoc:0,1,33,36,45,127,191,221(001018,2),221(0050f2,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,txpow:e002,extcap:0400000000000040|os:ios':
+ 'wifi4|probe:0,1,45,127,107,191,221(0050f2,8),221(001018,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,extcap:0400088400000040|assoc:0,1,33,36,45,127,191,221(001018,2),221(0050f2,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,txpow:e002,extcap:0400000000000040|name:ipad':
('iPad Mini', '4th gen', '5GHz'),
- 'wifi4|probe:0,1,45,127,107,191,221(0050f2,8),221(001018,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,extcap:0400088400000040|assoc:0,1,33,36,48,70,45,127,191,221(001018,2),221(0050f2,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,txpow:e002,extcap:0400000000000040|os:ios':
+ 'wifi4|probe:0,1,45,127,107,191,221(0050f2,8),221(001018,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,extcap:0400088400000040|assoc:0,1,33,36,48,70,45,127,191,221(001018,2),221(0050f2,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f815832,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,txpow:e002,extcap:0400000000000040|name:ipad':
('iPad Mini', '4th gen', '5GHz'),
'wifi4|probe:0,1,3,50|assoc:0,1,48,50|os:ios':
@@ -470,6 +470,9 @@
'wifi4|probe:0,1,50,3,45,127,107,221(0050f2,8),221(001018,2),htcap:002d,htagg:17,htmcs:0000ffff,extcap:0400088400000040|assoc:0,1,50,33,36,48,70,45,127,221(001018,2),221(0050f2,2),htcap:002d,htagg:17,htmcs:000000ff,txpow:1202,extcap:0000000000000040|os:ios':
('iPhone 6s/6s+', '', '2.4GHz'),
+ 'wifi4|probe:0,1,45,127,107,191,221(0017f2,10),221(0050f2,8),221(001018,2),htcap:006f,htagg:17,htmcs:000000ff,vhtcap:0f807032,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,extcap:00000884|assoc:0,1,33,36,48,70,54,45,127,191,199,221(0017f2,10),221(001018,2),221(0050f2,2),htcap:006f,htagg:17,htmcs:0000ffff,vhtcap:0f811032,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,txpow:13f9,extcap:000008|os:ios':
+ ('iPhone 7', '', '5GHz'),
+
'wifi4|probe:0,1,45,127,107,191,221(0050f2,8),221(001018,2),htcap:0063,htagg:17,htmcs:000000ff,vhtcap:0f805032,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,extcap:0400088400000040|assoc:0,1,33,36,45,127,221(001018,2),221(0050f2,2),htcap:0063,htagg:17,htmcs:000000ff,txpow:e002,extcap:000008|os:ios':
('iPhone SE', '', '5GHz'),
'wifi4|probe:0,1,50,3,45,127,107,221(0050f2,8),221(001018,2),htcap:0021,htagg:17,htmcs:000000ff,extcap:0400088400000040|assoc:0,1,50,33,36,45,127,221(001018,2),221(0050f2,2),htcap:0021,htagg:17,htmcs:000000ff,txpow:1402,extcap:0000000000000040|os:ios':
@@ -618,8 +621,6 @@
('Nexus 5', '', '5GHz'),
'wifi4|probe:0,1,3,45,127,191,221(001018,2),221(00904c,51),htcap:016f,htagg:17,htmcs:000000ff,vhtcap:0f805932,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,extcap:0000000000000040|assoc:0,1,33,36,48,45,127,191,221(001018,2),221(0050f2,2),htcap:016f,htagg:17,htmcs:000000ff,vhtcap:0f805932,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,txpow:e003,extcap:0000000000000040|oui:lg':
('Nexus 5', '', '5GHz'),
- 'wifi4|probe:0,1,45,127,191,221(001018,2),221(00904c,51),htcap:016f,htagg:17,htmcs:000000ff,vhtcap:0f805932,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,extcap:0000000000000040|assoc:0,1,33,36,48,45,127,191,221(001018,2),221(0050f2,2),htcap:016f,htagg:17,htmcs:000000ff,vhtcap:0f805932,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,txpow:e003,extcap:0000000000000040|oui:lg':
- ('Nexus 5', '', '5GHz'),
'wifi4|probe:0,1,45,127,191,221(001018,2),221(00904c,51),htcap:016f,htagg:17,htmcs:000000ff,vhtcap:0f805932,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,extcap:0000000000000040|assoc:0,1,33,36,45,127,191,221(001018,2),221(0050f2,2),htcap:016f,htagg:17,htmcs:000000ff,vhtcap:0f805932,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,txpow:e003,extcap:0000000000000040|oui:lg':
('Nexus 5', '', '5GHz'),
'wifi4|probe:0,1,45,127,107,191,221(506f9a,16),221(001018,2),221(00904c,51),221(00904c,4),221(0050f2,8),htcap:016f,htagg:17,htmcs:000000ff,vhtcap:0f805932,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,extcap:0000088001400040|assoc:0,1,33,36,48,45,127,70,191,221(001018,2),221(00904c,4),221(0050f2,2),htcap:016f,htagg:17,htmcs:000000ff,vhtcap:0f805932,vhtrxmcs:0000fffe,vhttxmcs:0000fffe,txpow:e003,extcap:0000008001400040|oui:lg':
@@ -788,6 +789,9 @@
'wifi4|probe:0,1,50,45,221(0050f2,4),htcap:01ad,htagg:02,htmcs:0000ffff,wps:WPS_SUPPLICANT_STATION|assoc:0,1,50,45,48,221(0050f2,2),htcap:01ad,htagg:02,htmcs:0000ffff|os:panasonictv':
('Panasonic TV', '', '2.4GHz'),
+ 'wifi4|probe:0,1|assoc:0,1,221(005043,1)|os:playstation':
+ ('Playstation', '3', '2.4GHz'),
+
'wifi4|probe:0,1,50|assoc:0,1,50,48,221(005043,1)|os:playstation':
('Playstation', '3 or 4', '2.4GHz'),
@@ -830,12 +834,6 @@
'wifi4|probe:0,1,50,3,45,127,221(001018,2),221(00904c,51),htcap:19bc,htagg:16,htmcs:0000ffff,extcap:0000000000000040|assoc:0,1,33,36,50,45,127,221(001018,2),221(0050f2,2),htcap:19bc,htagg:16,htmcs:0000ffff,txpow:140a,extcap:0000000000000040|os:roku':
('Roku', 'Streaming Stick 3600', '2.4GHz'),
- # Roku TV NP-YW
- 'wifi4|probe:0,1,45,127,191,221(001018,2),htcap:01ad,htagg:17,htmcs:0000ffff,vhtcap:0f8159b2,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,extcap:0000000000000040|assoc:0,1,33,36,48,45,127,191,199,221(001018,2),221(0050f2,2),htcap:01ad,htagg:17,htmcs:0000ffff,vhtcap:0f8159b2,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,txpow:1109,extcap:0000000000000040|os:roku':
- ('Roku TV', '', '5GHz'),
- 'wifi4|probe:0,1,50,3,45,221(001018,2),htcap:01ad,htagg:17,htmcs:0000ffff|assoc:0,1,50,33,36,48,45,221(001018,2),221(0050f2,2),htcap:01ad,htagg:17,htmcs:0000ffff,txpow:1209|os:roku':
- ('Roku TV', '', '2.4GHz'),
-
# Roku 1 models 2000, 2050, 2100, and XD
'wifi4|probe:0,1,50,45,221(001018,2),221(00904c,51),htcap:186e,htagg:1a,htmcs:0000ffff|assoc:0,1,33,36,48,50,45,221(001018,2),221(00904c,51),221(0050f2,2),htcap:186e,htagg:1a,htmcs:0000ffff,txpow:1308|os:roku':
('Roku', '1', '2.4GHz'),
@@ -866,15 +864,15 @@
'wifi4|probe:0,1,45,127,221(001018,2),221(00904c,51),htcap:093c,htagg:16,htmcs:0000ffff,extcap:0000000000000040|assoc:0,1,33,36,48,45,127,221(001018,2),221(0050f2,2),htcap:093c,htagg:16,htmcs:0000ffff,txpow:110a,extcap:0000000000000040|os:roku':
('Roku', '3', '5GHz'),
- # Roku 4 model 4400
+ # Roku 4 model 4400 or Roku TV NP-YW
'wifi4|probe:0,1,45,127,191,221(001018,2),htcap:01ad,htagg:17,htmcs:0000ffff,vhtcap:0f8159b2,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,extcap:0000000000000040|assoc:0,1,33,36,48,45,127,191,199,221(001018,2),221(0050f2,2),htcap:01ad,htagg:17,htmcs:0000ffff,vhtcap:0f8159b2,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,txpow:1109,extcap:0000000000000040|os:roku':
- ('Roku', '4', '5GHz'),
+ ('Roku', '4 or TV', '5GHz'),
'wifi4|probe:0,1,45,191,221(001018,2),htcap:01ad,htagg:17,htmcs:0000ffff,vhtcap:0f8159b2,vhtrxmcs:0000fffa,vhttxmcs:0000fffa|assoc:0,1,33,36,48,45,191,199,221(001018,2),221(0050f2,2),htcap:01ad,htagg:17,htmcs:0000ffff,vhtcap:0f8159b2,vhtrxmcs:0000fffa,vhttxmcs:0000fffa,txpow:1109|os:roku':
- ('Roku', '4', '5GHz'),
+ ('Roku', '4 or TV', '5GHz'),
'wifi4|probe:0,1,50,3,45,127,221(001018,2),htcap:01ad,htagg:17,htmcs:0000ffff,extcap:0000000000000040|assoc:0,1,50,33,36,48,45,221(001018,2),221(0050f2,2),htcap:01ad,htagg:17,htmcs:0000ffff,txpow:1209|os:roku':
- ('Roku', '4', '2.4GHz'),
+ ('Roku', '4 or TV', '2.4GHz'),
'wifi4|probe:0,1,50,3,45,221(001018,2),htcap:01ad,htagg:17,htmcs:0000ffff|assoc:0,1,50,33,36,48,45,221(001018,2),221(0050f2,2),htcap:01ad,htagg:17,htmcs:0000ffff,txpow:1209|os:roku':
- ('Roku', '4', '2.4GHz'),
+ ('Roku', '4 or TV', '2.4GHz'),
'wifi4|probe:0,1,50,3,45,htcap:0020,htagg:01,htmcs:000000ff|assoc:0,1,50,45,61,48,221(0050f2,2),htcap:0020,htagg:01,htmcs:000000ff|oui:samsung':
('Samsung Galaxy', 'Mini', '2.4GHz'),
@@ -1129,8 +1127,6 @@
('TiVo', 'BOLT', '2.4GHz'),
'wifi4|probe:0,1,50,3,45,127,221(001018,2),htcap:01ad,htagg:17,htmcs:0000ffff,extcap:0000008001000040|assoc:0,1,50,33,36,48,45,127,221(00904c,51),221(001018,2),221(0050f2,2),htcap:01ad,htagg:17,htmcs:0000ffff,txpow:1207,extcap:0000008001000040|os:tivo':
('TiVo', 'BOLT', '2.4GHz'),
- 'wifi4|probe:0,1,50,3,45,127,221(00904c,51),221(001018,2),htcap:01ad,htagg:17,htmcs:0000ffff,extcap:0000008001000040|assoc:0,1,50,33,36,48,45,127,221(00904c,51),221(001018,2),221(0050f2,2),htcap:01ad,htagg:17,htmcs:0000ffff,txpow:1207,extcap:0000008001000040|os:tivo':
- ('TiVo', 'BOLT', '2.4GHz'),
# TIVO-746
'wifi4|probe:0,1,50,221(00904c,51),45,48,htcap:13ce,htagg:1b,htmcs:0000ffff|assoc:0,1,33,36,50,221(0050f2,2),221(00904c,51),45,221(002163,1),221(002163,4),48,htcap:13ce,htagg:1b,htmcs:0000ffff,txpow:0f0f|os:tivo':
diff --git a/wifi/qca9880_cal.py b/wifi/qca9880_cal.py
new file mode 100755
index 0000000..4e5cc0c
--- /dev/null
+++ b/wifi/qca9880_cal.py
@@ -0,0 +1,240 @@
+#!/usr/bin/python -S
+
+"""Check and fix mis-calibrated QCA9880 modules on gfrg200/gfrg210.
+
+ Some modules were delivered to customers mis-calibrated. This script will
+ check if the module is affected, and if so, generate a patch that will be
+ used after driver reload.
+"""
+import glob
+import os
+import os.path
+import experiment
+import utils
+
+NO_CAL_EXPERIMENT = 'WifiNoCalibrationPatch'
+PLATFORM_FILE = '/etc/platform'
+CALIBRATION_DIR = '/tmp/ath10k_cal'
+CAL_PATCH_FILE = 'cal_data_patch.bin'
+ATH10K_CAL_DATA = '/sys/kernel/debug/ieee80211/phy[0-9]*/ath10k/cal_data'
+OUI_OFFSET = 6
+OUI_LEN = 3
+VERSION_OFFSET = 45
+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'
+
+
+def _log(msg):
+ utils.log('ath10k calibration: {}'.format(msg))
+
+
+def _is_ath10k(interface):
+ """Check if interface is driven by the ath10k driver.
+
+ Args:
+ interface: The interface to be checked. eg wlan1
+
+ Returns:
+ True if ath10k, otherwise False.
+ """
+ try:
+ return os.readlink(MODULE_PATH.format(interface)).find('ath10k')
+ except OSError:
+ return False
+
+
+def _oui_string(oui):
+ """Convert OUI from bytes to a string.
+
+ Args:
+ oui: OUI in byte format.
+
+ Returns:
+ OUI is string format separated by ':'. Eg. 88:dc:96.
+ """
+ return ':'.join('{:02x}'.format(ord(b)) for b in oui)
+
+
+def _version_string(version):
+ """Convert version from bytes to a string.
+
+ Args:
+ version: version in byte format.
+
+ Returns:
+ Three byte version string in hex format: 0x00 0x00 0x00
+ """
+
+ return ' '.join('0x{:02x}'.format(ord(b)) for b in version)
+
+
+def _is_module_miscalibrated():
+ """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.
+
+ Returns:
+ True if module is mis-calibrated, None if it can't be determined, and False
+ otherwise.
+ """
+
+ try:
+ cal_data_path = _ath10k_cal_data_path()
+ if cal_data_path is None:
+ return None
+
+ with open(cal_data_path, mode='rb') as f:
+ f.seek(OUI_OFFSET)
+ oui = f.read(OUI_LEN)
+ f.seek(VERSION_OFFSET)
+ version = f.read(VERSION_LEN)
+
+ except IOError as e:
+ _log('unable to open cal_data {}: {}'.format(cal_data_path, e.strerror))
+ return None
+
+ if oui not in (bytearray(s) for s in SUSPECT_OUIS):
+ _log('OUI {} is properly calibrated.'.format(_oui_string(oui)))
+ return False
+
+ if version != (bytearray(MISCALIBRATED_VERSION_FIELD)):
+ _log('version field {} signals proper calibration.'.
+ format(_version_string(version)))
+ return False
+
+ _log('May be mis-calibrated. OUI: {} version: {}'.
+ format(_oui_string(oui), _version_string(version)))
+
+ return True
+
+
+def _is_previously_calibrated():
+ """Check if this calibration script already ran since the last boot.
+
+ Returns:
+ True if calibration checks already ran, False otherwise.
+ """
+ return os.path.exists(CALIBRATION_DIR)
+
+
+def _create_calibration_dir():
+ """Create calibration directory.
+
+ Calibration directory contains the calibration patch file.
+ If the directory is empty it signals that calibration checks have already
+ run.
+
+ Returns:
+ True if directory exists or is created, false if any error.
+ """
+ try:
+ if not os.path.isdir(CALIBRATION_DIR):
+ os.makedirs(CALIBRATION_DIR)
+ return True
+ except OSError as e:
+ _log('unable to create calibration dir {}: {}.'.
+ format(CALIBRATION_DIR, e.strerror))
+ return False
+
+ return True
+
+
+def _ath10k_cal_data_path():
+ """Find the current path to cal data.
+
+ This path encodes the phy number, which is usually phy1, but if the
+ driver load order changed or if this runs after a reload, the phy
+ number will change.
+
+ Returns:
+ Path to cal_data in debugfs.
+ """
+
+ return glob.glob(ATH10K_CAL_DATA)[0]
+
+
+def _generate_calibration_patch():
+ """Create calibration patch and write to storage.
+
+ Returns:
+ True for success or False for failure.
+ """
+ try:
+ with open(_ath10k_cal_data_path(), mode='rb') as f:
+ cal_data = bytearray(f.read())
+ except IOError as e:
+ _log('cal patch: unable to open for read {}: {}.'.
+ 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
+
+ if not _create_calibration_dir():
+ return False
+
+ try:
+ patched_file = os.path.join(CALIBRATION_DIR, CAL_PATCH_FILE)
+ open(patched_file, 'wb').write(cal_data)
+ except IOError as e:
+ _log('unable to open for writing {}: {}.'.format(patched_file, e.strerror))
+ return False
+
+ return True
+
+
+def _reload_driver():
+ """Reload the ath10k driver so it picks up modified calibration file."""
+ ret = utils.subprocess_quiet(('rmmod', 'ath10k_pci'))
+ if ret != 0:
+ _log('rmmod ath10k_pci failed: {}.'.format(ret))
+ return
+
+ ret = utils.subprocess_quiet(('modprobe', 'ath10k_pci'))
+ if ret != 0:
+ _log('modprobe ath10k_pci failed: {}.'.format(ret))
+ return
+
+ _log('reload ath10k driver complete')
+
+
+def qca8990_calibration():
+ """Main QCA8990 calibration check."""
+
+ if experiment.enabled(NO_CAL_EXPERIMENT):
+ _log('experiment {} on. Skip calibration check.'.format(NO_CAL_EXPERIMENT))
+ return
+
+ if _is_previously_calibrated():
+ _log('calibration check completed earlier.')
+ return
+
+ if not _is_ath10k('wlan1'):
+ _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():
+ _log('generated new patch.')
+ _reload_driver()
+
+
+if __name__ == '__main__':
+ qca8990_calibration()
diff --git a/wifi/wifi.py b/wifi/wifi.py
index 4204791..34bb5e8 100755
--- a/wifi/wifi.py
+++ b/wifi/wifi.py
@@ -19,6 +19,7 @@
import iw
import options
import persist
+import qca9880_cal
import quantenna
import utils
@@ -254,6 +255,9 @@
'no wifi interface found for band=%s channel=%s suffix=%s',
band, channel, opt.interface_suffix)
+ # Check for calibration errors on ath10k.
+ qca9880_cal.qca8990_calibration()
+
found_active_config = False
for other_interface in (set(iw.find_all_interfaces_from_phy(phy)) -
set([interface])):