Merge "conman: Periodically log lowest-metric default route."
diff --git a/Makefile b/Makefile
index 921debb..b0d99f0 100644
--- a/Makefile
+++ b/Makefile
@@ -81,6 +81,10 @@
DIRS+=diags
endif
+ifeq ($(BR2_TARGET_GENERIC_PLATFORM_NAME),gflt110)
+DIRS+=diags
+endif
+
ifeq ($(BUILD_CONMAN),y)
DIRS+=conman
endif
diff --git a/cmds/Makefile b/cmds/Makefile
index 4f7db2b..24bc8a1 100644
--- a/cmds/Makefile
+++ b/cmds/Makefile
@@ -32,6 +32,7 @@
diskbench \
dnsck \
freemegs \
+ gfhd254_reboot \
gstatic \
http_bouncer \
ionice \
diff --git a/cmds/device_stats.proto b/cmds/device_stats.proto
index 30a344e..4f47b5e 100644
--- a/cmds/device_stats.proto
+++ b/cmds/device_stats.proto
@@ -17,5 +17,8 @@
// Device serial number.
optional string serial = 5;
+
+ // Public ipv6 address of onu
+ optional string ipv6 = 6;
};
diff --git a/cmds/gfhd254_reboot.c b/cmds/gfhd254_reboot.c
new file mode 100644
index 0000000..fdc7e32
--- /dev/null
+++ b/cmds/gfhd254_reboot.c
@@ -0,0 +1,65 @@
+// GFHD254 has a bug where software reset doesn't reset the entire
+// chip, some state in the SAGE engine isn't getting reset. This
+// drives a gpio that connects back to the chips own external reset
+// pin, resetting the chip with this pin works around the issue as
+// the SAGE engine is completely reset in this path.
+
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#define REG_BASE 0xf0410000
+#define REG_SIZE 0x8000
+
+
+#define GPIO_DATA (0x7404 / 4)
+#define GPIO_IODIR (0x7408 / 4)
+#define CTRL_MUX_0 (0x0700 / 4)
+#define CTRL_MUX_1 (0x0704 / 4)
+
+static void *mmap_(
+ void* addr, size_t size, int prot, int flags, int fd,
+ off_t offset) {
+#ifdef __ANDROID__
+ return mmap64(addr, size, prot, flags, fd,
+ (off64_t)(uint64_t)(uint32_t)offset);
+#else
+ return mmap(addr, size, prot, flags, fd, offset);
+#endif
+}
+
+// TODO(jnewlin): Revist this after the exact gpio being used
+// is settled on.
+
+int main() {
+ int fd = open("/dev/mem", O_RDWR);
+ volatile uint32_t* reg;
+
+ if (fd < 0) {
+ perror("mmap");
+ return 1;
+ }
+
+ reg = mmap_(NULL, REG_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
+ fd, REG_BASE);
+ if (reg == MAP_FAILED) {
+ perror("mmap");
+ return 1;
+ }
+
+ // Set the pin mux to gpio, value of zero selects gpio mode, this
+ // is the reset value so this is probably not required, but just
+ // in case.
+ reg[CTRL_MUX_0] &= ~((0xf << 8) | (0xf << 12)); // aon_gio2 and 3
+ reg[CTRL_MUX_1] &= ~(0xf << 4); // aon_gio9
+
+
+ // Set the direction to be an output and drive it low.
+ reg[GPIO_IODIR] &= ~((1 << 2) | (1 << 3) | (1 << 9));
+ reg[GPIO_DATA] &= ~((1 << 2) | (1 << 3) | (1 << 9));
+
+ return 0;
+}
diff --git a/cmds/statcatcher.cc b/cmds/statcatcher.cc
index 64db2b6..bfd7033 100644
--- a/cmds/statcatcher.cc
+++ b/cmds/statcatcher.cc
@@ -142,7 +142,8 @@
"onu_acs_contacted": %s,
"onu_acs_contact_time": "%lld",
"onu_uptime": %lld,
-"onu_serial": "%s"
+"onu_serial": "%s",
+"onu_ipv6": "%s"
})";
FILE *f = fopen(tmp_file.c_str(), "w");
if (!f) {
@@ -155,7 +156,8 @@
status.acs_contacted() ? "true" : "false",
status.acs_contact_time(),
status.uptime(),
- status.serial().c_str());
+ status.serial().c_str(),
+ status.ipv6().c_str());
fclose(f);
if (rename(tmp_file.c_str(), stat_file.c_str()) != 0) {
diff --git a/cmds/statpitcher.cc b/cmds/statpitcher.cc
index 412be5d..990666d 100644
--- a/cmds/statpitcher.cc
+++ b/cmds/statpitcher.cc
@@ -16,8 +16,10 @@
#include <fstream>
#include <iostream>
+#include <sstream>
#include <string>
#include <vector>
+#include <memory>
#include "device_stats.pb.h"
@@ -91,6 +93,71 @@
return static_cast<int64_t>(up);
}
+std::string IPAddress() {
+ std::ifstream infile;
+ infile.open("/proc/net/if_inet6");
+
+ if (!infile.good()) {
+ perror("error reading ipv6 from file");
+ exit(1);
+ }
+
+ std::string line;
+ int found = 0;
+ while (!infile.eof()) {
+ getline(infile, line);
+ // Want Ipv6 address on man interface
+ if (line.find("man") == std::string::npos) {
+ continue;
+ }
+ // Avoid local ipv6
+ if (line.substr(0, 4) == "0100" || // Discard prefix RFC 6666
+ line.substr(0, 2) == "fc" || // Unique local addresses
+ line.substr(0, 2) == "fd" ||
+ line.substr(0, 4) == "fe80" || // Link-local addresses
+ line.substr(0, 4) == "fec0") { // Old, deprecated local address range
+ continue;
+ }
+ found = 1;
+ break;
+ }
+
+ infile.close();
+ if (!found || line.size() < 32) {
+ perror("ipv6 address on man not found in file");
+ return "::1";
+ }
+
+ // Add colons
+ std::stringstream ipv6;
+ line = line.substr(0, 32);
+ for (unsigned int i = 0; i < line.size(); i++) {
+ if (i != 0 && i % 4 == 0) {
+ ipv6 << ':';
+ }
+ ipv6 << line[i];
+ }
+
+ // Format canonically
+ struct in6_addr ipv6_struct;
+ if (!inet_pton(AF_INET6, ipv6.str().c_str(), &ipv6_struct)) {
+ std::string errmsg = "unable to parse ipv6 address to inet_pton: " +
+ ipv6.str();
+ perror(errmsg.c_str());
+ exit(1);
+ }
+ char address[INET6_ADDRSTRLEN];
+ if (!inet_ntop(AF_INET6, &ipv6_struct, address, INET6_ADDRSTRLEN)) {
+ std::string errmsg = "unable to parse ipv6 address from inet_pton struct "
+ "created from: " + ipv6.str();
+ perror(errmsg.c_str());
+ exit(1);
+ }
+
+ std::string result(address);
+ return result;
+}
+
void MakePacket(std::vector<uint8_t>* pkt) {
devstatus::Status status;
@@ -101,6 +168,7 @@
status.set_acs_contact_time(acs_contact_time);
status.set_uptime(Uptime());
status.set_serial(serial_number);
+ status.set_ipv6(IPAddress());
pkt->resize(status.ByteSize());
status.SerializeToArray(&(*pkt)[0], status.ByteSize());
diff --git a/cmds/test-http_bouncer.sh b/cmds/test-http_bouncer.sh
index 4129d52..9cc0d9e 100755
--- a/cmds/test-http_bouncer.sh
+++ b/cmds/test-http_bouncer.sh
@@ -40,10 +40,6 @@
INPUTS[3]=$(printf "\n\n"; printf "$SENTINEL")
OUTPUTS[3]=$(printf "HTTP/1.0 302 Found\r\nLocation: $URL\r\n\r\n"; printf "$SENTINEL")
-INPUTS[4]=$(printf "GET /GIAG2.crl HTTP/1.0\r\nHost: pki.google.com\r\n\r\n"; printf "$SENTINEL")
-OUTPUTS[4]=$(curl "http://pki.google.com/GIAG2.crl"; printf "$SENTINEL")
-STRIP_HEADER[4]=1
-
WVSTART "http_bouncer test"
# fail with no arguments
@@ -59,10 +55,13 @@
i=0
while [ $i -lt ${#INPUTS[@]} ]; do
output=$(echo -n "${INPUTS[$i]}" | nc localhost $PORT; printf "$SENTINEL")
- if [ ${STRIP_HEADER[$i]} ]; then
- output=$(echo -n "$output" | sed '1,/^\r$/d')
- fi
-
WVPASSEQ "$output" "${OUTPUTS[$i]}"
i=$(expr $i + 1)
done
+
+# Make sure we can download a CRL even through the bouncer.
+# Some Internet Explorer versions will refuse to connect if we can't.
+WVPASS printf "GET /GIAG2.crl HTTP/1.0\r\nHost: pki.google.com\r\n\r\n" |\
+ nc localhost $PORT |\
+ sed '1,/^\r$/d' |\
+ openssl crl -inform DER
diff --git a/cmds/wifi_files.c b/cmds/wifi_files.c
index 49e77c6..1700cda 100644
--- a/cmds/wifi_files.c
+++ b/cmds/wifi_files.c
@@ -77,6 +77,11 @@
* client for a while longer than that.
*/
typedef struct client_state {
+ #define MAC_STR_LEN 18
+ char macstr[MAC_STR_LEN];
+ #define IFNAME_STR_LEN 16
+ char ifname[IFNAME_STR_LEN];
+
double inactive_since;
uint64_t rx_drop64;
@@ -106,14 +111,22 @@
uint32_t tx_failed;
uint32_t expected_mbps;
- int sample_index;
#define MAX_SAMPLE_INDEX 150
+ int rx_sample_index;
uint8_t rx_ht_mcs_samples[MAX_SAMPLE_INDEX];
uint8_t rx_vht_mcs_samples[MAX_SAMPLE_INDEX];
uint8_t rx_width_samples[MAX_SAMPLE_INDEX];
uint8_t rx_ht_nss_samples[MAX_SAMPLE_INDEX];
uint8_t rx_vht_nss_samples[MAX_SAMPLE_INDEX];
- uint8_t short_gi_samples[MAX_SAMPLE_INDEX];
+ uint8_t rx_short_gi_samples[MAX_SAMPLE_INDEX];
+
+ int tx_sample_index;
+ uint8_t tx_ht_mcs_samples[MAX_SAMPLE_INDEX];
+ uint8_t tx_vht_mcs_samples[MAX_SAMPLE_INDEX];
+ uint8_t tx_width_samples[MAX_SAMPLE_INDEX];
+ uint8_t tx_ht_nss_samples[MAX_SAMPLE_INDEX];
+ uint8_t tx_vht_nss_samples[MAX_SAMPLE_INDEX];
+ uint8_t tx_short_gi_samples[MAX_SAMPLE_INDEX];
/*
* Clients spend a lot of time mostly idle, where they
@@ -131,7 +144,14 @@
uint8_t rx_width;
uint8_t rx_ht_nss;
uint8_t rx_vht_nss;
- uint8_t short_gi;
+ uint8_t rx_short_gi;
+
+ uint8_t tx_ht_mcs;
+ uint8_t tx_vht_mcs;
+ uint8_t tx_width;
+ uint8_t tx_ht_nss;
+ uint8_t tx_vht_nss;
+ uint8_t tx_short_gi;
/* Track the largest value we've ever seen from this client. This
* shows client capabilities, even if current interference
@@ -141,7 +161,14 @@
uint8_t rx_max_width;
uint8_t rx_max_ht_nss;
uint8_t rx_max_vht_nss;
- uint8_t ever_short_gi;
+ uint8_t ever_rx_short_gi;
+
+ uint8_t tx_max_ht_mcs;
+ uint8_t tx_max_vht_mcs;
+ uint8_t tx_max_width;
+ uint8_t tx_max_ht_nss;
+ uint8_t tx_max_vht_nss;
+ uint8_t ever_tx_short_gi;
int8_t signal;
int8_t signal_avg;
@@ -153,11 +180,6 @@
uint8_t mfp:1;
uint8_t tdls_peer:1;
uint8_t preamble_length:1;
-
- #define MAC_STR_LEN 18
- char macstr[MAC_STR_LEN];
- #define IFNAME_STR_LEN 16
- char ifname[IFNAME_STR_LEN];
} client_state_t;
@@ -176,6 +198,16 @@
static FILE *wifi_info_handle = NULL;
+static void ClearClientStateCounters(client_state_t *state)
+{
+ char macstr[MAC_STR_LEN];
+
+ memcpy(macstr, state->macstr, sizeof(macstr));
+ memset(state, 0, sizeof(*state));
+ memcpy(state->macstr, macstr, sizeof(state->macstr));
+}
+
+
static int GetIfIndex(const char *ifname)
{
int fd;
@@ -349,7 +381,7 @@
}
-static void GetRxMCS(struct nlattr *attr,
+static void GetMCS(struct nlattr *attr,
int *mcs, int *vht_mcs, int *width, int *short_gi, int *vht_nss)
{
int w160 = 0, w80_80 = 0, w80 = 0, w40 = 0;
@@ -418,7 +450,7 @@
}
-static int RxHtMcsToNss(int rxmcs)
+static int HtMcsToNss(int rxmcs)
{
/* https://en.wikipedia.org/wiki/IEEE_802.11n-2009 */
switch(rxmcs) {
@@ -488,6 +520,12 @@
mac = (uint8_t *)nla_data(tb[NL80211_ATTR_MAC]);
state = FindClientState(mac);
+
+ if (strcasecmp(state->ifname, ifname) != 0) {
+ /* Client moved from one interface to another */
+ ClearClientStateCounters(state);
+ }
+
state->last_seen = monotime();
snprintf(state->ifname, sizeof(state->ifname), "%s", ifname);
@@ -502,20 +540,20 @@
}
if (si[NL80211_STA_INFO_RX_BITRATE]) {
- int rx_ht_mcs=0, rx_vht_mcs=0, rx_vht_nss=0, rx_width=0, short_gi=0;
+ int rx_ht_mcs=0, rx_vht_mcs=0, rx_vht_nss=0, rx_width=0, rx_short_gi=0;
int ht_nss;
- int n = state->sample_index + 1;
+ int n = state->rx_sample_index + 1;
if (n >= MAX_SAMPLE_INDEX) n = 0;
state->rx_bitrate = GetBitrate(si[NL80211_STA_INFO_RX_BITRATE]);
- GetRxMCS(si[NL80211_STA_INFO_RX_BITRATE], &rx_ht_mcs, &rx_vht_mcs,
- &rx_width, &short_gi, &rx_vht_nss);
+ GetMCS(si[NL80211_STA_INFO_RX_BITRATE], &rx_ht_mcs, &rx_vht_mcs,
+ &rx_width, &rx_short_gi, &rx_vht_nss);
state->rx_ht_mcs_samples[n] = rx_ht_mcs;
if (rx_ht_mcs > state->rx_max_ht_mcs) state->rx_max_ht_mcs = rx_ht_mcs;
- ht_nss = RxHtMcsToNss(rx_ht_mcs);
+ ht_nss = HtMcsToNss(rx_ht_mcs);
state->rx_ht_nss_samples[n] = ht_nss;
if (ht_nss > state->rx_max_ht_nss) state->rx_max_ht_nss = ht_nss;
@@ -525,13 +563,13 @@
state->rx_vht_nss_samples[n] = rx_vht_nss;
if (rx_vht_nss > state->rx_max_vht_nss) state->rx_max_vht_nss = rx_vht_nss;
- state->short_gi_samples[n] = short_gi;
- if (short_gi) state->ever_short_gi = 1;
+ state->rx_short_gi_samples[n] = rx_short_gi;
+ if (rx_short_gi) state->ever_rx_short_gi = 1;
state->rx_width_samples[n] = rx_width;
if (rx_width > state->rx_max_width) state->rx_max_width = rx_width;
- state->sample_index = n;
+ state->rx_sample_index = n;
}
if (si[NL80211_STA_INFO_RX_BYTES]) {
uint32_t last_rx_bytes = state->rx_bytes;
@@ -544,7 +582,36 @@
state->rx_packets64 += (state->rx_packets - last_rx_packets);
}
if (si[NL80211_STA_INFO_TX_BITRATE]) {
+ int tx_ht_mcs=0, tx_vht_mcs=0, tx_vht_nss=0, tx_width=0, tx_short_gi=0;
+ int ht_nss;
+ int n = state->tx_sample_index + 1;
+
+ if (n >= MAX_SAMPLE_INDEX) n = 0;
+
state->tx_bitrate = GetBitrate(si[NL80211_STA_INFO_TX_BITRATE]);
+ GetMCS(si[NL80211_STA_INFO_TX_BITRATE], &tx_ht_mcs, &tx_vht_mcs,
+ &tx_width, &tx_short_gi, &tx_vht_nss);
+
+ state->tx_ht_mcs_samples[n] = tx_ht_mcs;
+ if (tx_ht_mcs > state->tx_max_ht_mcs) state->tx_max_ht_mcs = tx_ht_mcs;
+
+ ht_nss = HtMcsToNss(tx_ht_mcs);
+ state->tx_ht_nss_samples[n] = ht_nss;
+ if (ht_nss > state->tx_max_ht_nss) state->tx_max_ht_nss = ht_nss;
+
+ state->tx_vht_mcs_samples[n] = tx_vht_mcs;
+ if (tx_vht_mcs > state->tx_max_vht_mcs) state->tx_max_vht_mcs = tx_vht_mcs;
+
+ state->tx_vht_nss_samples[n] = tx_vht_nss;
+ if (tx_vht_nss > state->tx_max_vht_nss) state->tx_max_vht_nss = tx_vht_nss;
+
+ state->tx_short_gi_samples[n] = tx_short_gi;
+ if (tx_short_gi) state->ever_tx_short_gi = 1;
+
+ state->tx_width_samples[n] = tx_width;
+ if (tx_width > state->tx_max_width) state->tx_max_width = tx_width;
+
+ state->tx_sample_index = n;
}
if (si[NL80211_STA_INFO_TX_BYTES]) {
uint32_t last_tx_bytes = state->tx_bytes;
@@ -655,7 +722,9 @@
client_state_t *state = (client_state_t *)value;
int i;
uint8_t rx_ht_mcs=0, rx_vht_mcs=0, rx_width=0, rx_ht_nss=0;
- uint8_t rx_vht_nss=0, short_gi=0;
+ uint8_t rx_vht_nss=0, rx_short_gi=0;
+ uint8_t tx_ht_mcs=0, tx_vht_mcs=0, tx_width=0, tx_ht_nss=0;
+ uint8_t tx_vht_nss=0, tx_short_gi=0;
for (i = 0; i < MAX_SAMPLE_INDEX; ++i) {
if (state->rx_ht_mcs_samples[i] > rx_ht_mcs) {
@@ -673,8 +742,27 @@
if (state->rx_vht_nss_samples[i] > rx_vht_nss) {
rx_vht_nss = state->rx_vht_nss_samples[i];
}
- if (state->short_gi_samples[i] > short_gi) {
- short_gi = state->short_gi_samples[i];
+ if (state->rx_short_gi_samples[i] > rx_short_gi) {
+ rx_short_gi = state->rx_short_gi_samples[i];
+ }
+
+ if (state->tx_ht_mcs_samples[i] > tx_ht_mcs) {
+ tx_ht_mcs = state->tx_ht_mcs_samples[i];
+ }
+ if (state->tx_vht_mcs_samples[i] > tx_vht_mcs) {
+ tx_vht_mcs = state->tx_vht_mcs_samples[i];
+ }
+ if (state->tx_width_samples[i] > tx_width) {
+ tx_width = state->tx_width_samples[i];
+ }
+ if (state->tx_ht_nss_samples[i] > tx_ht_nss) {
+ tx_ht_nss = state->tx_ht_nss_samples[i];
+ }
+ if (state->tx_vht_nss_samples[i] > tx_vht_nss) {
+ tx_vht_nss = state->tx_vht_nss_samples[i];
+ }
+ if (state->tx_short_gi_samples[i] > tx_short_gi) {
+ tx_short_gi = state->tx_short_gi_samples[i];
}
}
@@ -683,7 +771,14 @@
state->rx_width = rx_width;
state->rx_ht_nss = rx_ht_nss;
state->rx_vht_nss = rx_vht_nss;
- state->short_gi = short_gi;
+ state->rx_short_gi = rx_short_gi;
+
+ state->tx_ht_mcs = tx_ht_mcs;
+ state->tx_vht_mcs = tx_vht_mcs;
+ state->tx_width = tx_width;
+ state->tx_ht_nss = tx_ht_nss;
+ state->tx_vht_nss = tx_vht_nss;
+ state->tx_short_gi = tx_short_gi;
}
@@ -738,8 +833,8 @@
fprintf(f, " \"rx max vht_nss\": %u,\n", state->rx_max_vht_nss);
#define BOOL(x) (x ? "true" : "false")
- fprintf(f, " \"rx SHORT_GI\": %s,\n", BOOL(state->short_gi));
- fprintf(f, " \"rx SHORT_GI seen\": %s,\n", BOOL(state->ever_short_gi));
+ fprintf(f, " \"rx SHORT_GI\": %s,\n", BOOL(state->rx_short_gi));
+ fprintf(f, " \"rx SHORT_GI seen\": %s,\n", BOOL(state->ever_rx_short_gi));
#undef BOOL
fprintf(f, " \"signal\": %hhd,\n", state->signal);
@@ -797,6 +892,8 @@
"%s %s %ld %" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64
" %c,%hhd,%hhd,%u,%u,%u,%u,%u,%d"
" %u,%u,%u,%u,%u,%d"
+ " %u,%u,%u,%u,%u,%d"
+ " %u,%u,%u,%u,%u,%d"
"\n",
state->macstr, state->ifname,
((mono_now - state->last_seen) + (state->inactive_msec / 1000)),
@@ -810,12 +907,21 @@
state->signal, state->signal_avg,
state->rx_ht_mcs, state->rx_ht_nss,
state->rx_vht_mcs, state->rx_vht_nss,
- state->rx_width, state->short_gi,
+ state->rx_width, state->rx_short_gi,
/* information about the maximum we've ever seen from this client. */
state->rx_max_ht_mcs, state->rx_max_ht_nss,
state->rx_max_vht_mcs, state->rx_max_vht_nss,
- state->rx_max_width, state->ever_short_gi);
+ state->rx_max_width, state->ever_rx_short_gi,
+
+ state->tx_ht_mcs, state->tx_ht_nss,
+ state->tx_vht_mcs, state->tx_vht_nss,
+ state->tx_width, state->tx_short_gi,
+
+ /* information about the maximum we've ever seen from this client. */
+ state->tx_max_ht_mcs, state->tx_max_ht_nss,
+ state->tx_max_vht_mcs, state->tx_max_vht_nss,
+ state->tx_max_width, state->ever_tx_short_gi);
}
@@ -878,8 +984,9 @@
if ((data[i] <= 0x1f) || !isprint(data[i])) {
fprintf(f, "\\u00%02x", data[i]);
} else {
- fprintf(f, "%c", data[i]); break;
+ fprintf(f, "%c", data[i]);
}
+ break;
}
}
}
diff --git a/cmds/wifi_files_test.c b/cmds/wifi_files_test.c
index 9d48dd1..902cd73 100644
--- a/cmds/wifi_files_test.c
+++ b/cmds/wifi_files_test.c
@@ -50,6 +50,27 @@
}
+void testPrintSsidEscapedQuoteBackslash()
+{
+ FILE *f = tmpfile();
+ char buf[32];
+ const uint8_t ssid[] = {'"', '\\'}; /* not NUL terminated. */
+ const uint8_t expected[] = {'\\', '"', '\\', '\\'};
+
+ printf("Testing \"%s\" in %s:\n", __FUNCTION__, __FILE__);
+ memset(buf, 0, sizeof(buf));
+ TEST_ASSERT(f != NULL);
+ print_ssid_escaped(f, sizeof(ssid), ssid);
+ fflush(f);
+ rewind(f);
+ TEST_ASSERT(fread(buf, 1, sizeof(buf), f) > 0);
+ printf("%s\n", buf);
+ TEST_ASSERT(memcmp(buf, expected, sizeof(expected)) == 0);
+ fclose(f);
+ printf("! %s:%d\t%s\tok\n", __FILE__, __LINE__, __FUNCTION__);
+}
+
+
void testFrequencyToChannel()
{
printf("Testing \"%s\" in %s:\n", __FUNCTION__, __FILE__);
@@ -171,6 +192,7 @@
clients = g_hash_table_new(g_str_hash, g_str_equal);
testPrintSsidEscaped();
+ testPrintSsidEscapedQuoteBackslash();
testFrequencyToChannel();
testClientStateToJson();
testAgeOutClients();
diff --git a/conman/connection_manager.py b/conman/connection_manager.py
index 858f338..374d495 100755
--- a/conman/connection_manager.py
+++ b/conman/connection_manager.py
@@ -79,7 +79,7 @@
'-s': 'ssid',
'--ssid': 'ssid',
'-S': 'interface_suffix',
- '--interface_suffix': 'interface_suffix',
+ '--interface-suffix': 'interface_suffix',
}
attr = None
for line in self.command:
@@ -91,7 +91,7 @@
attr = binwifi_option_attrs.get(line, None)
if line.startswith('WIFI_PSK='):
- self.passphrase = line.split('WIFI_PSK=')[-1]
+ self.passphrase = line[len('WIFI_PSK='):]
if self.ssid is None:
raise ValueError('Command file does not specify SSID')
@@ -170,6 +170,7 @@
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._status.wlan_failed = True
return False
return True
@@ -212,6 +213,7 @@
COMMAND_FILE_REGEXP = WLAN_FILE_REGEXP_FMT % COMMAND_FILE_PREFIX
ACCESS_POINT_FILE_REGEXP = WLAN_FILE_REGEXP_FMT % ACCESS_POINT_FILE_PREFIX
GATEWAY_FILE_PREFIX = 'gateway.'
+ SUBNET_FILE_PREFIX = 'subnet.'
MOCA_NODE_FILE_PREFIX = 'node'
WIFI_SETCLIENT = ['wifi', 'setclient']
IFUP = ['ifup']
@@ -295,6 +297,7 @@
self._wpa_control_interface)
for path, prefix in ((self._tmp_dir, self.GATEWAY_FILE_PREFIX),
+ (self._tmp_dir, self.SUBNET_FILE_PREFIX),
(self._interface_status_dir, ''),
(self._moca_tmp_dir, self.MOCA_NODE_FILE_PREFIX),
(self._config_dir, self.COMMAND_FILE_PREFIX)):
@@ -583,7 +586,7 @@
"""Update the contents of /tmp/hosts."""
lowest_metric_interface = None
for ifc in [self.bridge] + self.wifi:
- route = ifc.current_route()
+ route = ifc.current_routes().get('default', None)
if route:
metric = route.get('metric', 0)
# Skip temporary connection_check routes.
@@ -691,6 +694,14 @@
logging.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)
+
elif path == self._moca_tmp_dir:
match = re.match(r'^%s\d+$' % self.MOCA_NODE_FILE_PREFIX, filename)
if match:
diff --git a/conman/connection_manager_test.py b/conman/connection_manager_test.py
index 1f90f96..7cf1785 100755
--- a/conman/connection_manager_test.py
+++ b/conman/connection_manager_test.py
@@ -208,11 +208,12 @@
#
# 1) Write an interface status file.
# 2) Call run-dhclient, which would call dhclient-script, which would
- # write a gateway file.
+ # call ipapply, which would write gateway and subnet files.
#
# Fake both of these things instead.
self.write_interface_status_file('1')
self.write_gateway_file()
+ self.write_subnet_file()
def stop_client(self):
client_was_up = self.client_up
@@ -233,6 +234,13 @@
# This value doesn't matter to conman, so it's fine to hard code it here.
f.write('192.168.1.1')
+ def write_subnet_file(self):
+ subnet_file = os.path.join(self.tmp_dir,
+ self.subnet_file_prefix + self.wifi.name)
+ with open(subnet_file, 'w') as f:
+ # This value doesn't matter to conman, so it's fine to hard code it here.
+ f.write('192.168.1.0/24')
+
def write_interface_status_file(self, value):
status_file = os.path.join(self.interface_status_dir, self.wifi.name)
with open(status_file, 'w') as f:
@@ -240,6 +248,21 @@
f.write(value)
+@wvtest.wvtest
+def WLANConfigurationParseTest(): # pylint: disable=invalid-name
+ """Test WLANConfiguration parsing."""
+ cmd = '\n'.join([
+ 'WIFI_PSK=abcdWIFI_PSK=qwer', 'wifi', 'set', '-P', '-b', '5',
+ '--bridge=br0', '-s', 'my ssid=1', '--interface-suffix', '_suffix',
+ ])
+ config = WLANConfiguration('5', interface_test.Wifi('wcli0', 20), cmd, None,
+ None)
+
+ wvtest.WVPASSEQ('my ssid=1', config.ssid)
+ wvtest.WVPASSEQ('abcdWIFI_PSK=qwer', config.passphrase)
+ wvtest.WVPASSEQ('_suffix', config.interface_suffix)
+
+
class Wifi(interface_test.Wifi):
def __init__(self, *args, **kwargs):
@@ -374,6 +397,7 @@
wlan_configuration.tmp_dir = self._tmp_dir
wlan_configuration.interface_status_dir = self._interface_status_dir
wlan_configuration.gateway_file_prefix = self.GATEWAY_FILE_PREFIX
+ wlan_configuration.subnet_file_prefix = self.SUBNET_FILE_PREFIX
super(ConnectionManager, self)._update_wlan_configuration(
wlan_configuration)
@@ -394,6 +418,8 @@
if up and not dhcp_failure:
self.write_gateway_file('br0' if interface_name in ('eth0', 'moca0')
else interface_name)
+ self.write_subnet_file('br0' if interface_name in ('eth0', 'moca0')
+ else interface_name)
def _binwifi(self, *command):
super(ConnectionManager, self)._binwifi(*command)
@@ -438,6 +464,13 @@
# This value doesn't matter to conman, so it's fine to hard code it here.
f.write('192.168.1.1')
+ def write_subnet_file(self, interface_name):
+ subnet_file = os.path.join(self._tmp_dir,
+ self.SUBNET_FILE_PREFIX + interface_name)
+ with open(subnet_file, 'w') as f:
+ # This value doesn't matter to conman, so it's fine to hard code it here.
+ f.write('192.168.1.0/24')
+
def write_interface_status_file(self, interface_name, value):
status_file = os.path.join(self._interface_status_dir, interface_name)
with open(status_file, 'w') as f:
@@ -616,10 +649,10 @@
c.run_once()
wvtest.WVPASS(c.acs())
wvtest.WVPASS(c.internet())
- wvtest.WVPASS(c.bridge.current_route())
+ wvtest.WVPASS(c.bridge.current_routes())
wvtest.WVPASS(os.path.exists(acs_autoprov_filepath))
for wifi in c.wifi:
- wvtest.WVFAIL(wifi.current_route())
+ wvtest.WVFAIL(wifi.current_routes_normal_testonly())
wvtest.WVFAIL(c.has_status_files([status.P.CONNECTED_TO_WLAN,
status.P.HAVE_CONFIG]))
@@ -628,7 +661,7 @@
c.run_once()
wvtest.WVFAIL(c.acs())
wvtest.WVFAIL(c.internet())
- wvtest.WVFAIL(c.bridge.current_route())
+ wvtest.WVFAIL(c.bridge.current_routes_normal_testonly())
wvtest.WVFAIL(os.path.exists(acs_autoprov_filepath))
wvtest.WVFAIL(c.has_status_files([status.P.CAN_REACH_ACS,
status.P.CAN_REACH_INTERNET]))
@@ -638,35 +671,35 @@
c.run_once()
wvtest.WVPASS(c.acs())
wvtest.WVPASS(c.internet())
- wvtest.WVPASS(c.bridge.current_route())
+ wvtest.WVPASS(c.bridge.current_routes())
# Bring up ethernet, access via both moca and ethernet.
c.set_ethernet(True)
c.run_once()
wvtest.WVPASS(c.acs())
wvtest.WVPASS(c.internet())
- wvtest.WVPASS(c.bridge.current_route())
+ wvtest.WVPASS(c.bridge.current_routes())
# Bring down moca, still have access via ethernet.
c.set_moca(False)
c.run_once()
wvtest.WVPASS(c.acs())
wvtest.WVPASS(c.internet())
- wvtest.WVPASS(c.bridge.current_route())
+ wvtest.WVPASS(c.bridge.current_routes())
# The bridge interfaces are up, but they can't reach anything.
c.bridge.set_connection_check_result('fail')
c.run_until_interface_update()
wvtest.WVFAIL(c.acs())
wvtest.WVFAIL(c.internet())
- wvtest.WVFAIL(c.bridge.current_route())
+ wvtest.WVFAIL(c.bridge.current_routes_normal_testonly())
# Now c connects to a restricted network.
c.bridge.set_connection_check_result('restricted')
c.run_until_interface_update()
wvtest.WVPASS(c.acs())
wvtest.WVFAIL(c.internet())
- wvtest.WVPASS(c.bridge.current_route())
+ wvtest.WVPASS(c.bridge.current_routes())
# Now the wired connection goes away.
c.set_ethernet(False)
@@ -674,7 +707,9 @@
c.run_once()
wvtest.WVFAIL(c.acs())
wvtest.WVFAIL(c.internet())
- wvtest.WVFAIL(c.bridge.current_route())
+ # We have no links, so we should have no routes (not even low priority ones),
+ # and /tmp/hosts should only contain a line for localhost.
+ wvtest.WVFAIL(c.bridge.current_routes())
check_tmp_hosts('127.0.0.1 localhost')
# Now there are some scan results.
@@ -696,7 +731,7 @@
wvtest.WVPASS(c.acs())
wvtest.WVPASS(c.internet())
wvtest.WVFAIL(c.client_up(band))
- wvtest.WVPASS(c.wifi_for_band(band).current_route())
+ wvtest.WVPASS(c.wifi_for_band(band).current_routes())
wvtest.WVPASSEQ(c.log_upload_count, 1)
# Disable scan results again.
c.interface_with_scan_results = None
@@ -710,7 +745,7 @@
c.disable_access_point(band)
c.run_once()
wvtest.WVPASS(c.client_up(band))
- wvtest.WVPASS(c.wifi_for_band(band).current_route())
+ wvtest.WVPASS(c.wifi_for_band(band).current_routes())
wvtest.WVPASS(c.has_status_files([status.P.CONNECTED_TO_WLAN]))
# Kill wpa_supplicant. conman should restart it.
@@ -751,7 +786,7 @@
c.disable_access_point(band)
c.run_once()
wvtest.WVPASS(c.client_up(band))
- wvtest.WVPASS(c.wifi_for_band(band).current_route())
+ wvtest.WVPASS(c.wifi_for_band(band).current_routes())
wvtest.WVPASS(c.has_status_files([status.P.CONNECTED_TO_WLAN]))
# Now enable the AP. Since we have no wired connection, this should have no
@@ -759,8 +794,8 @@
c.enable_access_point(band)
c.run_once()
wvtest.WVPASS(c.client_up(band))
- wvtest.WVPASS(c.wifi_for_band(band).current_route())
- wvtest.WVFAIL(c.bridge.current_route())
+ wvtest.WVPASS(c.wifi_for_band(band).current_routes())
+ wvtest.WVFAIL(c.bridge.current_routes_normal_testonly())
c.run_until_interface_update()
check_tmp_hosts('192.168.1.100 %s\n127.0.0.1 localhost' % hostname)
@@ -772,8 +807,8 @@
c.run_until_interface_update()
wvtest.WVPASS(c.access_point_up(band))
wvtest.WVFAIL(c.client_up(band))
- wvtest.WVFAIL(c.wifi_for_band(band).current_route())
- wvtest.WVPASS(c.bridge.current_route())
+ wvtest.WVFAIL(c.wifi_for_band(band).current_routes())
+ wvtest.WVPASS(c.bridge.current_routes())
check_tmp_hosts('192.168.1.101 %s\n127.0.0.1 localhost' % hostname)
# Now move (rather than delete) the configuration file. The AP should go
@@ -785,8 +820,8 @@
c.run_once()
wvtest.WVFAIL(c.access_point_up(band))
wvtest.WVFAIL(c.client_up(band))
- wvtest.WVFAIL(c.wifi_for_band(band).current_route())
- wvtest.WVPASS(c.bridge.current_route())
+ wvtest.WVFAIL(c.wifi_for_band(band).current_routes_normal_testonly())
+ wvtest.WVPASS(c.bridge.current_routes())
wvtest.WVFAIL(c.has_status_files([status.P.HAVE_CONFIG]))
# Now move it back, and the AP should come back.
@@ -794,8 +829,8 @@
c.run_once()
wvtest.WVPASS(c.access_point_up(band))
wvtest.WVFAIL(c.client_up(band))
- wvtest.WVFAIL(c.wifi_for_band(band).current_route())
- wvtest.WVPASS(c.bridge.current_route())
+ wvtest.WVFAIL(c.wifi_for_band(band).current_routes_normal_testonly())
+ wvtest.WVPASS(c.bridge.current_routes())
# Now delete the config and bring down the bridge and make sure we reprovision
# via the last working BSS.
@@ -805,7 +840,9 @@
c.run_until_interface_update()
wvtest.WVFAIL(c.acs())
wvtest.WVFAIL(c.internet())
- check_tmp_hosts('127.0.0.1 localhost')
+ # We still have a link and might be wrong about the connection_check, so
+ # /tmp/hosts should still contain a line for this hostname.
+ check_tmp_hosts('192.168.1.101 %s\n127.0.0.1 localhost' % hostname)
# s3 is not what the cycler would suggest trying next.
wvtest.WVPASSNE('s3', c.wifi_for_band(band).cycler.peek())
# Run only once, so that only one BSS can be tried. It should be the s3 one,
@@ -979,11 +1016,11 @@
c.run_once()
wvtest.WVPASS(c.access_point_up('2.4'))
wvtest.WVPASS(c.access_point_up('5'))
- wvtest.WVPASS(c.bridge.current_route())
+ wvtest.WVPASS(c.bridge.current_routes())
wvtest.WVFAIL(c.client_up('2.4'))
wvtest.WVFAIL(c.client_up('5'))
- wvtest.WVFAIL(c.wifi_for_band('2.4').current_route())
- wvtest.WVFAIL(c.wifi_for_band('5').current_route())
+ wvtest.WVFAIL(c.wifi_for_band('2.4').current_routes_normal_testonly())
+ wvtest.WVFAIL(c.wifi_for_band('5').current_routes_normal_testonly())
# Disable the 2.4 GHz AP, make sure the 5 GHz AP stays up. 2.4 GHz should
# join the WLAN.
@@ -992,9 +1029,9 @@
wvtest.WVFAIL(c.access_point_up('2.4'))
wvtest.WVPASS(c.access_point_up('5'))
wvtest.WVPASS(c.client_up('2.4'))
- wvtest.WVPASS(c.bridge.current_route())
- wvtest.WVPASS(c.wifi_for_band('2.4').current_route())
- wvtest.WVFAIL(c.wifi_for_band('5').current_route())
+ wvtest.WVPASS(c.bridge.current_routes())
+ wvtest.WVPASS(c.wifi_for_band('2.4').current_routes())
+ wvtest.WVFAIL(c.wifi_for_band('5').current_routes_normal_testonly())
# Delete the 2.4 GHz WLAN configuration; it should leave the WLAN but nothing
# else should change.
@@ -1003,9 +1040,9 @@
wvtest.WVFAIL(c.access_point_up('2.4'))
wvtest.WVPASS(c.access_point_up('5'))
wvtest.WVFAIL(c.client_up('2.4'))
- wvtest.WVPASS(c.bridge.current_route())
- wvtest.WVFAIL(c.wifi_for_band('2.4').current_route())
- wvtest.WVFAIL(c.wifi_for_band('5').current_route())
+ wvtest.WVPASS(c.bridge.current_routes())
+ wvtest.WVFAIL(c.wifi_for_band('2.4').current_routes_normal_testonly())
+ wvtest.WVFAIL(c.wifi_for_band('5').current_routes_normal_testonly())
# Disable the wired connection and remove the WLAN configurations. Both
# radios should scan. Wait for 5 GHz to scan, then enable scan results for
@@ -1014,18 +1051,18 @@
c.set_ethernet(False)
c.run_once()
wvtest.WVFAIL(c.acs())
- wvtest.WVFAIL(c.bridge.current_route())
- wvtest.WVFAIL(c.wifi_for_band('2.4').current_route())
- wvtest.WVFAIL(c.wifi_for_band('5').current_route())
+ wvtest.WVFAIL(c.bridge.current_routes_normal_testonly())
+ wvtest.WVFAIL(c.wifi_for_band('2.4').current_routes_normal_testonly())
+ wvtest.WVFAIL(c.wifi_for_band('5').current_routes_normal_testonly())
# The 5 GHz scan has no results.
c.run_until_scan('5')
c.run_once()
c.run_until_interface_update()
wvtest.WVFAIL(c.acs())
- wvtest.WVFAIL(c.bridge.current_route())
- wvtest.WVFAIL(c.wifi_for_band('2.4').current_route())
- wvtest.WVFAIL(c.wifi_for_band('5').current_route())
+ wvtest.WVFAIL(c.bridge.current_routes_normal_testonly())
+ wvtest.WVFAIL(c.wifi_for_band('2.4').current_routes_normal_testonly())
+ wvtest.WVFAIL(c.wifi_for_band('5').current_routes_normal_testonly())
# The next 2.4 GHz scan will have results.
c.interface_with_scan_results = c.wifi_for_band('2.4').name
@@ -1035,9 +1072,9 @@
c.run_once()
c.run_until_interface_update()
wvtest.WVPASS(c.acs())
- wvtest.WVFAIL(c.bridge.current_route())
- wvtest.WVPASS(c.wifi_for_band('2.4').current_route())
- wvtest.WVFAIL(c.wifi_for_band('5').current_route())
+ wvtest.WVFAIL(c.bridge.current_routes_normal_testonly())
+ wvtest.WVPASS(c.wifi_for_band('2.4').current_routes())
+ wvtest.WVFAIL(c.wifi_for_band('5').current_routes_normal_testonly())
c.run_once()
wvtest.WVPASSEQ(c.log_upload_count, 1)
@@ -1085,9 +1122,9 @@
c.run_once()
wvtest.WVFAIL(c.access_point_up('2.4'))
wvtest.WVPASS(c.access_point_up('5'))
- wvtest.WVPASS(c.bridge.current_route())
- wvtest.WVFAIL(c.wifi_for_band('2.4').current_route())
- wvtest.WVFAIL(c.wifi_for_band('5').current_route())
+ wvtest.WVPASS(c.bridge.current_routes())
+ wvtest.WVFAIL(c.wifi_for_band('2.4').current_routes_normal_testonly())
+ wvtest.WVFAIL(c.wifi_for_band('5').current_routes_normal_testonly())
# Disable the 2.4 GHz AP; nothing should change. The 2.4 GHz client should
# not be up because the same radio is being used to run a 5 GHz AP.
@@ -1096,9 +1133,9 @@
wvtest.WVFAIL(c.access_point_up('2.4'))
wvtest.WVPASS(c.access_point_up('5'))
wvtest.WVFAIL(c.client_up('2.4'))
- wvtest.WVPASS(c.bridge.current_route())
- wvtest.WVFAIL(c.wifi_for_band('2.4').current_route())
- wvtest.WVFAIL(c.wifi_for_band('5').current_route())
+ wvtest.WVPASS(c.bridge.current_routes())
+ wvtest.WVFAIL(c.wifi_for_band('2.4').current_routes_normal_testonly())
+ wvtest.WVFAIL(c.wifi_for_band('5').current_routes_normal_testonly())
# Delete the 2.4 GHz WLAN configuration; nothing should change.
c.delete_wlan_config('2.4')
@@ -1106,9 +1143,9 @@
wvtest.WVFAIL(c.access_point_up('2.4'))
wvtest.WVPASS(c.access_point_up('5'))
wvtest.WVFAIL(c.client_up('2.4'))
- wvtest.WVPASS(c.bridge.current_route())
- wvtest.WVFAIL(c.wifi_for_band('2.4').current_route())
- wvtest.WVFAIL(c.wifi_for_band('5').current_route())
+ wvtest.WVPASS(c.bridge.current_routes())
+ wvtest.WVFAIL(c.wifi_for_band('2.4').current_routes_normal_testonly())
+ wvtest.WVFAIL(c.wifi_for_band('5').current_routes_normal_testonly())
# Disable the wired connection and remove the WLAN configurations. There
# should be a single scan that leads to ACS access. (It doesn't matter which
@@ -1118,9 +1155,9 @@
c.set_ethernet(False)
c.run_once()
wvtest.WVFAIL(c.acs())
- wvtest.WVFAIL(c.bridge.current_route())
- wvtest.WVFAIL(c.wifi_for_band('2.4').current_route())
- wvtest.WVFAIL(c.wifi_for_band('5').current_route())
+ wvtest.WVFAIL(c.bridge.current_routes_normal_testonly())
+ wvtest.WVFAIL(c.wifi_for_band('2.4').current_routes_normal_testonly())
+ wvtest.WVFAIL(c.wifi_for_band('5').current_routes_normal_testonly())
# The scan will have results that will lead to ACS access.
c.interface_with_scan_results = c.wifi_for_band('2.4').name
@@ -1129,9 +1166,9 @@
c.run_once()
c.run_until_interface_update()
wvtest.WVPASS(c.acs())
- wvtest.WVFAIL(c.bridge.current_route())
- wvtest.WVPASS(c.wifi_for_band('2.4').current_route())
- wvtest.WVPASS(c.wifi_for_band('5').current_route())
+ wvtest.WVFAIL(c.bridge.current_routes_normal_testonly())
+ wvtest.WVPASS(c.wifi_for_band('2.4').current_routes())
+ wvtest.WVPASS(c.wifi_for_band('5').current_routes())
c.run_once()
wvtest.WVPASSEQ(c.log_upload_count, 1)
@@ -1176,7 +1213,7 @@
c.run_once()
wvtest.WVPASS(c.wifi_for_band('2.4').acs())
wvtest.WVPASS(c.wifi_for_band('2.4').internet())
- wvtest.WVPASS(c.wifi_for_band('2.4').current_route())
+ wvtest.WVPASS(c.wifi_for_band('2.4').current_routes())
@wvtest.wvtest
@@ -1189,7 +1226,7 @@
c: The ConnectionManager set up by @connection_manager_test.
"""
wvtest.WVPASS(c._connected_to_wlan(c.wifi_for_band('2.4')))
- wvtest.WVPASS(c.wifi_for_band('2.4').current_route)
+ wvtest.WVPASS(c.wifi_for_band('2.4').current_routes())
@wvtest.wvtest
diff --git a/conman/interface.py b/conman/interface.py
index e172a82..2d0fbbe 100755
--- a/conman/interface.py
+++ b/conman/interface.py
@@ -7,13 +7,18 @@
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
METRIC_24GHZ = 22
-METRIC_TEMPORARY_CONNECTION_CHECK = 99
+
+RFC2385_MULTICAST_ROUTE = '239.0.0.0/8'
experiment.register('WifiSimulateWireless')
CWMP_PATH = '/tmp/cwmp'
@@ -30,7 +35,7 @@
IP_ROUTE = ['ip', 'route']
IP_ADDR_SHOW = ['ip', 'addr', 'show', 'dev']
- def __init__(self, name, metric):
+ def __init__(self, name, base_metric):
self.name = name
# Currently connected links for this interface, e.g. ethernet.
@@ -40,13 +45,18 @@
self._has_acs = None
self._has_internet = None
- # The gateway IP for this interface.
+ self._subnet = None
self._gateway_ip = None
- self.metric = metric
+ self.base_metric = base_metric
+ self.metric_offset = 0
# Until this is set True, the routing table will not be touched.
self._initialized = False
+ @property
+ def metric(self):
+ return str(int(self.base_metric) + self.metric_offset)
+
def _connection_check(self, check_acs):
"""Check this interface's connection status.
@@ -72,18 +82,7 @@
' (ACS)' if check_acs else '', self.name)
return False
- # Temporarily add a route to make sure the connection check can be run.
- # Give it a high metric so that it won't interfere with normal default
- # routes.
- added_temporary_route = False
- if not self.current_route():
- logging.debug('Adding temporary connection check route for dev %s',
- self.name)
- self._ip_route('add', 'default',
- 'via', self._gateway_ip,
- 'dev', self.name,
- 'metric', str(METRIC_TEMPORARY_CONNECTION_CHECK))
- added_temporary_route = True
+ self.add_routes()
cmd = [self.CONNECTION_CHECK, '-I', self.name]
if check_acs:
@@ -96,14 +95,6 @@
self.name,
'passed' if result else 'failed')
- # Delete the temporary route.
- if added_temporary_route:
- logging.debug('Deleting temporary connection check route for dev %s',
- self.name)
- self._ip_route('del', 'default',
- 'dev', self.name,
- 'metric', str(METRIC_TEMPORARY_CONNECTION_CHECK))
-
return result
def gateway(self):
@@ -121,59 +112,110 @@
return self._has_internet
- def add_route(self):
- """Adds a default route for this interface.
+ def add_routes(self):
+ """Update default routes for this interface.
- First, checks whether an equivalent route already exists, and if so,
- returns.
+ 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)
return
- if self._gateway_ip is None:
- logging.info('Cannot add route for %s without a gateway IP.', self.name)
- return
-
- # If the current default route is the same, there is nothing to do. If it
+ # If the current routes are the same, there is nothing to do. If either
# exists but is different, delete it before adding an updated one.
- current = self.current_route()
- if current:
- if (current.get('via', None) == self._gateway_ip and
- current.get('metric', None) == str(self.metric)):
- return
- else:
- self.delete_route()
+ current = self.current_routes()
- logging.debug('Adding default route for dev %s', self.name)
- self._ip_route('add', 'default',
- 'via', self._gateway_ip,
- 'dev', self.name,
- 'metric', str(self.metric))
+ to_add = []
- def delete_route(self):
- while self.current_route():
- logging.debug('Deleting default route for dev %s', self.name)
- self._ip_route('del', 'default',
- 'dev', self.name)
+ subnet = current.get('subnet', {})
+ 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)
+ to_add.append(('subnet', ('add', self._subnet, 'dev', self.name,
+ 'metric', str(self.metric))))
+ subnet = self._subnet
+ else:
+ subnet = None
+ self.delete_route('default', 'subnet')
- def current_route(self):
- """Read the current default route for this interface.
+ default = current.get('default', {})
+ if self._gateway_ip:
+ 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)
+ to_add.append(('default',
+ ('add', 'default', 'via', self._gateway_ip,
+ 'dev', self.name, 'metric', str(self.metric))))
+ else:
+ self.delete_route('default')
+
+ # RFC2365 multicast route.
+ if current.get('multicast', {}).get('metric', None) != str(self.metric):
+ logging.debug('Adding multicast route for dev %s', self.name)
+ to_add.append(('multicast', ('add', RFC2385_MULTICAST_ROUTE,
+ 'dev', self.name,
+ 'metric', str(self.metric))))
+
+ for route_type, _ in to_add[::-1]:
+ self.delete_route(route_type)
+
+ for _, cmd in to_add:
+ self._ip_route(*cmd)
+
+ def delete_route(self, *args):
+ """Delete default and/or subnet routes for this interface.
+
+ Args:
+ *args: Which routes to delete. Must be at least one of 'default',
+ 'subnet', 'multicast'.
+
+ Raises:
+ ValueError: If neither default nor subnet is True.
+ """
+ args = set(args)
+ args &= set(('default', 'subnet', 'multicast'))
+ if not args:
+ raise ValueError(
+ 'Must specify at least one of default, subnet, multicast to delete.')
+
+ # 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._ip_route('del', self.current_routes()[route_type]['route'],
+ 'dev', self.name)
+
+ def current_routes(self):
+ """Read the current routes for this interface.
Returns:
- A dict containing the gateway [and metric] of the route, or an empty dict
- if there is currently no default route for this interface.
+ A dict mapping 'default' and/or 'subnet' to a dict containing the gateway
+ [and metric] of the route. Only contains keys for routes that are
+ present.
"""
result = {}
for line in self._ip_route().splitlines():
- if line.startswith('default') and 'dev %s' % self.name in line:
- key = None
+ if 'dev %s' % self.name in line:
+ if line.startswith('default'):
+ route_type = 'default'
+ elif re.search(r'/\d{1,2}$', line.split()[0]):
+ route_type = 'subnet'
+ else:
+ continue
+ route = {}
+ key = 'route'
for token in line.split():
if token in ['via', 'metric']:
key = token
elif key:
- result[key] = token
+ if key == 'route' and token == RFC2385_MULTICAST_ROUTE:
+ route_type = 'multicast'
+ route[key] = token
key = None
+ if route:
+ result[route_type] = route
return result
@@ -183,17 +225,17 @@
' '.join(self.IP_ROUTE), ' '.join(args))
return ''
- return self._really_ip_route(*args)
-
- def _really_ip_route(self, *args):
try:
logging.debug('%s calling ip route %s', self.name, ' '.join(args))
- return subprocess.check_output(self.IP_ROUTE + list(args))
+ return self._really_ip_route(*args)
except subprocess.CalledProcessError as e:
logging.error('Failed to call "ip route" with args %r: %s', args,
e.message)
return ''
+ def _really_ip_route(self, *args):
+ return subprocess.check_output(self.IP_ROUTE + list(args))
+
def _ip_addr_show(self):
try:
return subprocess.check_output(self.IP_ADDR_SHOW + [self.name])
@@ -209,7 +251,12 @@
def set_gateway_ip(self, gateway_ip):
logging.info('New gateway IP %s for %s', gateway_ip, self.name)
self._gateway_ip = gateway_ip
- self.update_routes()
+ self.update_routes(expire_cache=True)
+
+ def set_subnet(self, subnet):
+ logging.info('New subnet %s for %s', subnet, self.name)
+ self._subnet = subnet
+ self.update_routes(expire_cache=True)
def _set_link_status(self, link, is_up):
"""Set whether a link is up or not."""
@@ -243,36 +290,51 @@
def update_routes(self, expire_cache=True):
"""Update this interface's routes.
- If the interface has gained ACS or internet access, add a route. If it had
- either and now has neither, delete the route.
+ If the interface has ACS or internet access, prioritize its routes. If it
+ doesn't but has a link, deprioritize the routes. If it has no links, delete
+ the routes.
Args:
expire_cache: If true, force a recheck of connection status before
- deciding whether to add or remove routes.
+ deciding how to prioritize routes.
"""
logging.debug('Updating routes for %s', self.name)
- maybe_had_acs = self._has_acs
- maybe_had_internet = self._has_internet
-
if expire_cache:
self.expire_connection_status_cache()
- has_acs = self.acs()
- has_internet = self.internet()
+ if self.acs() or self.internet():
+ self.prioritize_routes()
+ else:
+ # If we still have a link, just deprioritize the routes, in case we're
+ # wrong about the connection check. If there's no actual link, then
+ # really delete the routes.
+ if self.links:
+ self.deprioritize_routes()
+ else:
+ self.delete_route('default', 'subnet', 'multicast')
- # This is a little confusing: We want to try adding a route if we _may_
- # have gone from no access to some access, and we want to try deleting the
- # route if we _may_ have lost *all* access. So the first condition checks
- # for truthiness but the elif checks for explicit Falsity (i.e. excluding
- # the None/unknown case).
- had_access = maybe_had_acs or maybe_had_internet
- # pylint: disable=g-explicit-bool-comparison
- maybe_had_access = maybe_had_acs != False or maybe_had_internet != False
- has_access = has_acs or has_internet
- if not had_access and has_access:
- self.add_route()
- elif maybe_had_access and not has_access:
- self.delete_route()
+ def prioritize_routes(self):
+ """When connection check succeeds, route priority (metric) should be normal.
+
+ This is the inverse of deprioritize_routes.
+ """
+ if not self._initialized:
+ return
+ logging.info('%s routes have normal priority', self.name)
+ self.metric_offset = 0
+ self.add_routes()
+
+ def deprioritize_routes(self):
+ """When connection check fails, deprioritize routes by increasing metric.
+
+ This is conservative alternative to deleting routes, in case we are mistaken
+ about route not providing a useful connection.
+ """
+ if not self._initialized:
+ return
+ logging.info('%s routes have low priority', self.name)
+ self.metric_offset = 50
+ self.add_routes()
def initialize(self):
"""Tell the interface it has its initial state.
@@ -319,16 +381,22 @@
self._moca_stations.remove(node_id)
self.moca = bool(self._moca_stations)
- def add_route(self):
+ def prioritize_routes(self):
"""We only want ACS autoprovisioning when we're using a wired route."""
- super(Bridge, self).add_route()
+ super(Bridge, self).prioritize_routes()
open(self._acs_autoprovisioning_filepath, 'w')
- def delete_route(self):
+ def deprioritize_routes(self, *args, **kwargs):
"""We only want ACS autoprovisioning when we're using a wired route."""
if os.path.exists(self._acs_autoprovisioning_filepath):
os.unlink(self._acs_autoprovisioning_filepath)
- super(Bridge, self).delete_route()
+ super(Bridge, self).deprioritize_routes(*args, **kwargs)
+
+ def delete_route(self, *args, **kwargs):
+ """We only want ACS autoprovisioning when we're using a wired route."""
+ if os.path.exists(self._acs_autoprovisioning_filepath):
+ os.unlink(self._acs_autoprovisioning_filepath)
+ super(Bridge, self).delete_route(*args, **kwargs)
def _connection_check(self, check_acs):
"""Support for WifiSimulateWireless."""
@@ -528,7 +596,8 @@
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)
+ security = (self._qcsapi('ssid_get_authentication_mode', 'wifi0', ssid)
+ if ssid else None)
except subprocess.CalledProcessError:
# If QCSAPI failed, skip update.
return
diff --git a/conman/interface_test.py b/conman/interface_test.py
index 13dcf14..79c58ae 100755
--- a/conman/interface_test.py
+++ b/conman/interface_test.py
@@ -5,6 +5,9 @@
import logging
import os
import shutil
+import socket
+import struct
+import subprocess
import tempfile
import time
@@ -38,6 +41,13 @@
self.routing_table = {}
self.ip_testonly = None
+ def _connection_check(self, *args, **kwargs):
+ result = super(FakeInterfaceMixin, self)._connection_check(*args, **kwargs)
+ if (self.current_routes().get('default', {}).get('via', None) !=
+ self._gateway_ip):
+ return False
+ return result
+
def set_connection_check_result(self, result):
if result in ['succeed', 'fail', 'restricted']:
# pylint: disable=invalid-name
@@ -46,27 +56,58 @@
raise ValueError('Invalid fake connection_check script.')
def _really_ip_route(self, *args):
+ def can_add_route():
+ def ip_to_int(ip):
+ return struct.unpack('!I', socket.inet_pton(socket.AF_INET, ip))[0]
+
+ if args[1] != 'default':
+ return True
+
+ via = ip_to_int(args[args.index('via') + 1])
+ for (ifc, route, _), _ in self.routing_table.iteritems():
+ if ifc != self.name:
+ continue
+
+ netmask = 0
+ if '/' in route:
+ route, netmask = route.split('/')
+ netmask = 32 - int(netmask)
+ route = ip_to_int(route)
+
+ if (route >> netmask) == (via >> netmask):
+ return True
+
+ return False
+
if not args:
return '\n'.join(self.routing_table.values() +
- ['1.2.3.4/24 dev %s proto kernel scope link' % self.name,
+ ['1.2.3.4/24 dev fake0 proto kernel scope link',
+ # Non-subnet route, e.g. to NFS host.
+ '1.2.3.1 dev %s proto kernel scope link' % self.name,
'default via 1.2.3.4 dev fake0',
'random junk'])
metric = None
if 'metric' in args:
metric = args[args.index('metric') + 1]
- key = (self.name, metric)
+ if args[0] in ('add', 'del'):
+ route = args[1]
+ key = (self.name, route, metric)
if args[0] == 'add' and key not in self.routing_table:
+ if not can_add_route():
+ raise subprocess.CalledProcessError(
+ 'Tried to add default route without subnet route: %r',
+ self.routing_table)
logging.debug('Adding route for %r', key)
self.routing_table[key] = ' '.join(args[1:])
elif args[0] == 'del':
if key in self.routing_table:
logging.debug('Deleting route for %r', key)
del self.routing_table[key]
- elif key[1] is None:
+ elif key[2] is None:
# pylint: disable=g-builtin-op
for k in self.routing_table.keys():
- if k[0] == key[0]:
+ if k[:-1] == key[:-1]:
logging.debug('Deleting route for %r (generalized from %s)', k, key)
del self.routing_table[k]
break
@@ -77,6 +118,10 @@
return ''
+ def current_routes_normal_testonly(self):
+ result = self.current_routes()
+ return {k: v for k, v in result.iteritems() if int(v.get('metric', 0)) < 50}
+
class Bridge(FakeInterfaceMixin, interface.Bridge):
pass
@@ -86,8 +131,8 @@
"""Fake wpactrl.WPACtrl."""
# pylint: disable=unused-argument
- def __init__(self, socket):
- self._socket = socket
+ def __init__(self, wpa_socket):
+ self._socket = wpa_socket
self.events = []
self.attached = False
self.connected = False
@@ -330,59 +375,106 @@
wvtest.WVFAIL(b.acs())
wvtest.WVFAIL(b.internet())
- wvtest.WVFAIL(b.current_route())
+ wvtest.WVFAIL(b.current_routes())
+ wvtest.WVFAIL(b.current_routes_normal_testonly())
wvtest.WVFAIL(os.path.exists(autoprov_filepath))
b.add_moca_station(0)
+ wvtest.WVFAIL(os.path.exists(autoprov_filepath))
+ b.set_subnet('192.168.1.0/24')
b.set_gateway_ip('192.168.1.1')
+ wvtest.WVFAIL(os.path.exists(autoprov_filepath))
# Everything should fail because the interface is not initialized.
wvtest.WVFAIL(b.acs())
wvtest.WVFAIL(b.internet())
- wvtest.WVFAIL(b.current_route())
+ wvtest.WVFAIL(b.current_routes_normal_testonly())
wvtest.WVFAIL(os.path.exists(autoprov_filepath))
b.initialize()
wvtest.WVPASS(b.acs())
wvtest.WVPASS(b.internet())
- wvtest.WVPASS(b.current_route())
+ current_routes = b.current_routes()
+ wvtest.WVPASSEQ(len(current_routes), 3)
+ wvtest.WVPASS('default' in current_routes)
+ wvtest.WVPASS('subnet' in current_routes)
+ wvtest.WVPASS('multicast' in current_routes)
wvtest.WVPASS(os.path.exists(autoprov_filepath))
b.add_moca_station(1)
wvtest.WVPASS(b.acs())
wvtest.WVPASS(b.internet())
- wvtest.WVPASS(b.current_route())
+ wvtest.WVPASSEQ(len(b.current_routes()), 3)
wvtest.WVPASS(os.path.exists(autoprov_filepath))
b.remove_moca_station(0)
b.remove_moca_station(1)
wvtest.WVFAIL(b.acs())
wvtest.WVFAIL(b.internet())
- wvtest.WVFAIL(b.current_route())
+ # We have no links, so should have no routes.
+ wvtest.WVFAIL(b.current_routes())
wvtest.WVFAIL(os.path.exists(autoprov_filepath))
b.add_moca_station(2)
wvtest.WVPASS(b.acs())
wvtest.WVPASS(b.internet())
- wvtest.WVPASS(b.current_route())
+ wvtest.WVPASSEQ(len(b.current_routes()), 3)
wvtest.WVPASS(os.path.exists(autoprov_filepath))
b.set_connection_check_result('fail')
b.update_routes()
wvtest.WVFAIL(b.acs())
wvtest.WVFAIL(b.internet())
- wvtest.WVFAIL(b.current_route())
+ # We have links but the connection check failed, so we should only have a
+ # low priority route, i.e. metric at least 50.
+ wvtest.WVPASSEQ(len(b.current_routes()), 3)
+ wvtest.WVFAIL(b.current_routes_normal_testonly())
wvtest.WVFAIL(os.path.exists(autoprov_filepath))
b.set_connection_check_result('restricted')
b.update_routes()
wvtest.WVPASS(b.acs())
wvtest.WVFAIL(b.internet())
- wvtest.WVPASS(b.current_route())
+ wvtest.WVPASSEQ(len(b.current_routes()), 3)
wvtest.WVPASS(os.path.exists(autoprov_filepath))
wvtest.WVFAIL(b.get_ip_address())
b.ip_testonly = '192.168.1.100'
wvtest.WVPASSEQ(b.get_ip_address(), '192.168.1.100')
+ # Get a new gateway/subnet (e.g. due to joining a new network).
+ # Not on the subnet; adding IP should fail.
+ b.set_gateway_ip('192.168.2.1')
+ wvtest.WVFAIL('default' in b.current_routes())
+ wvtest.WVPASS('subnet' in b.current_routes())
+ # Without a default route, the connection check should fail.
+ wvtest.WVFAIL(b.acs())
+
+ # Now we get the subnet and should add updated subnet and gateway routes.
+ b.set_subnet('192.168.2.0/24')
+ wvtest.WVPASSEQ(b.current_routes()['default']['via'], '192.168.2.1')
+ wvtest.WVPASSLE(int(b.current_routes()['default']['metric']), 50)
+ wvtest.WVPASSEQ(b.current_routes()['subnet']['route'], '192.168.2.0/24')
+ wvtest.WVPASSLE(int(b.current_routes()['subnet']['metric']), 50)
+ wvtest.WVPASS(b.acs())
+
+ # If we have no subnet, make sure that both subnet and default routes are
+ # removed.
+ b.set_subnet(None)
+ wvtest.WVFAIL('subnet' in b.current_routes())
+ wvtest.WVFAIL('default' in b.current_routes())
+
+ # Now repeat the new-network test, but with a faulty connection. Make sure
+ # the metrics are set appropriately.
+ b.set_connection_check_result('fail')
+ b.set_subnet('192.168.3.0/24')
+ b.set_gateway_ip('192.168.3.1')
+ wvtest.WVPASSGE(int(b.current_routes()['default']['metric']), 50)
+ wvtest.WVPASSGE(int(b.current_routes()['subnet']['metric']), 50)
+
+ # Now test deleting only the gateway IP.
+ b.set_gateway_ip(None)
+ wvtest.WVPASS('subnet' in b.current_routes())
+ wvtest.WVFAIL('default' in b.current_routes())
+
finally:
shutil.rmtree(tmp_dir)
@@ -485,6 +577,7 @@
b = Bridge('br0', '10', acs_autoprovisioning_filepath=autoprov_filepath)
b.add_moca_station(0)
b.set_gateway_ip('192.168.1.1')
+ b.set_subnet('192.168.1.0/24')
b.set_connection_check_result('succeed')
b.initialize()
diff --git a/conman/status.py b/conman/status.py
index e21dc01..7f75682 100644
--- a/conman/status.py
+++ b/conman/status.py
@@ -20,6 +20,7 @@
TRYING_OPEN = 'TRYING_OPEN'
TRYING_WLAN = 'TRYING_WLAN'
+ WLAN_FAILED = 'WLAN_FAILED'
CONNECTED_TO_OPEN = 'CONNECTED_TO_OPEN'
CONNECTED_TO_WLAN = 'CONNECTED_TO_WLAN'
HAVE_CONFIG = 'HAVE_CONFIG'
@@ -43,6 +44,10 @@
(),
(P.TRYING_OPEN, P.CONNECTED_TO_OPEN, P.CONNECTED_TO_WLAN)
),
+ P.WLAN_FAILED: (
+ (),
+ (P.TRYING_WLAN, P.CONNECTED_TO_WLAN)
+ ),
P.CONNECTED_TO_OPEN: (
(),
(P.CONNECTED_TO_WLAN, P.TRYING_OPEN, P.TRYING_WLAN)
diff --git a/diags/Makefile b/diags/Makefile
index 76855ce..399c44a 100644
--- a/diags/Makefile
+++ b/diags/Makefile
@@ -7,6 +7,9 @@
ifeq ($(BR2_TARGET_GENERIC_PLATFORM_NAME),gfsc100)
DIRS += spacecast
endif
+ifeq ($(BR2_TARGET_GENERIC_PLATFORM_NAME),gflt110)
+ DIRS += chameleon
+endif
PYTHON?=python
diff --git a/diags/chameleon/Makefile b/diags/chameleon/Makefile
new file mode 100644
index 0000000..e6af150
--- /dev/null
+++ b/diags/chameleon/Makefile
@@ -0,0 +1,42 @@
+default: all
+
+BINARY = diags
+
+TARGETS=$(BINARY)
+INSTALL=install
+PREFIX=$(DESTDIR)/usr
+BINDIR=$(PREFIX)/sbin
+LIBDIR=$(PREFIX)/lib
+INCLUDEDIR=$(PREFIX)/include
+
+CC=$(CROSS_COMPILE)gcc
+CXX=$(CROSS_COMPILE)g++
+RM=rm -f
+
+CFLAGS = -Wall -Werror -Wimplicit -Wno-unknown-pragmas -D_GNU_SOURC -g
+CFLAGS += $(EXTRA_CFLAGS)
+LDFLAGS += $(EXTRA_LDFLAGS)
+
+IFLAGS += $(patsubst %,-I%,$(INC_DIRS))
+CFILES = $(wildcard ../common/*.c *.c)
+OFILES = $(patsubst %.c,%.o,$(CFILES))
+
+all: $(TARGETS)
+
+install:
+ $(INSTALL) -m 0755 $(BINARY) $(BINDIR)/
+
+install-libs:
+ @:
+
+test:
+ @:
+
+$(BINARY): $(OFILES)
+ $(CC) $^ $(LDFLAGS) -o $@
+
+%.o: %.c
+ $(CC) $(CFLAGS) $(IFLAGS) -c $^ -c
+
+clean:
+ $(RM) $(OFILES) $(BINARY)
diff --git a/diags/chameleon/common.h b/diags/chameleon/common.h
new file mode 100644
index 0000000..f790704
--- /dev/null
+++ b/diags/chameleon/common.h
@@ -0,0 +1,14 @@
+/*
+ * (C) Copyright 2015 Google, Inc.
+ * All rights reserved.
+ *
+ */
+
+#ifndef VENDOR_GOOGLE_DIAGS_LOCKDOWN_COMMON_H_
+#define VENDOR_GOOGLE_DIAGS_LOCKDOWN_COMMON_H_
+
+#define MAX_PKT_SIZE 4096
+#define FAIL_TEXT "FAILED:"
+#define PASS_TEXT "PASSED:"
+
+#endif // VENDOR_GOOGLE_DIAGS_LOCKDOWN_COMMON_H_
diff --git a/diags/chameleon/datapath.c b/diags/chameleon/datapath.c
new file mode 100644
index 0000000..d5da3c4
--- /dev/null
+++ b/diags/chameleon/datapath.c
@@ -0,0 +1,248 @@
+/*
+ * (C) Copyright 2015 Google, Inc.
+ * All rights reserved.
+ *
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "../common/io.h"
+#include "../common/util.h"
+
+#define AVANTA_BASE_ADDR 0xF1000000
+#define GPON_RECV_STATUS_FEC0 (AVANTA_BASE_ADDR + 0x000AC80C)
+#define GPON_RECV_STATUS_FEC1 (AVANTA_BASE_ADDR + 0x000AC810)
+#define GPON_RECV_STATUS_FEC2 (AVANTA_BASE_ADDR + 0x000AC814)
+#define GPON_RECV_STATUS_SUPER_FRAME_CNT (AVANTA_BASE_ADDR + 0x000AC818)
+#define PON_PHY_TEST_PRBS_COUNTER_0 (AVANTA_BASE_ADDR + 0x000A2E70)
+#define PON_PHY_TEST_PRBS_COUNTER_1 (AVANTA_BASE_ADDR + 0x000A2E74)
+#define PON_PHY_TEST_PRBS_COUNTER_2 (AVANTA_BASE_ADDR + 0x000A2E78)
+#define PON_PHY_TEST_PRBS_ERROR_COUNTER_0 (AVANTA_BASE_ADDR + 0x000A2E7C)
+#define PON_PHY_TEST_PRBS_ERROR_COUNTER_1 (AVANTA_BASE_ADDR + 0x000A2E80)
+#define PON_PHY_CTRL0 (AVANTA_BASE_ADDR + 0x000184F4)
+#define PON_PHY_RESET_BIT 0x8
+
+static int set_pon_phy_out_of_reset() {
+ unsigned int phy_ctrl0;
+
+ if (read_physical_addr(PON_PHY_CTRL0, &phy_ctrl0) != 0) {
+ printf("Read address 0x%x failed\n", PON_PHY_CTRL0);
+ return -1;
+ }
+ if (phy_ctrl0 & PON_PHY_RESET_BIT) {
+ phy_ctrl0 &= ~PON_PHY_RESET_BIT;
+ if (write_physical_addr(PON_PHY_CTRL0, phy_ctrl0) != 0) {
+ printf("Write address 0x%x value 0x%x failed\n", PON_PHY_CTRL0,
+ phy_ctrl0);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static void soc_reg_read_usage(void) {
+ printf("soc_reg_read <addr>\n");
+ printf("read Marvell 88F6601 registers\n");
+ printf("Example:\n");
+ printf("soc_reg_read 0x00018810\n");
+}
+
+int soc_reg_read(int argc, char *argv[]) {
+ unsigned int reg_addr, addr, value;
+
+ if (argc != 2) {
+ soc_reg_read_usage();
+ return -1;
+ }
+
+ reg_addr = strtoul(argv[1], NULL, 16);
+ addr = reg_addr + AVANTA_BASE_ADDR;
+ if (read_physical_addr(addr, &value) != 0) {
+ printf("Read address 0x%x failed\n", addr);
+ return -1;
+ }
+ printf("0x%x = 0x%x\n", reg_addr, value);
+
+ return 0;
+}
+
+static void soc_reg_write_usage(void) {
+ printf("soc_reg_write <addr> <data>\n");
+ printf("write Marvell 88F6601 registers\n");
+ printf("Example:\n");
+ printf("soc_reg_write 0x0007241C 0x0\n");
+}
+
+int soc_reg_write(int argc, char *argv[]) {
+ unsigned int reg_addr, addr, value;
+
+ if (argc != 3) {
+ soc_reg_write_usage();
+ return -1;
+ }
+
+ reg_addr = strtoul(argv[1], NULL, 16);
+ value = strtoul(argv[2], NULL, 16);
+ addr = reg_addr + AVANTA_BASE_ADDR;
+ if (write_physical_addr(addr, value) != 0) {
+ printf("Write address 0x%x value 0x%x failed\n", addr, value);
+ return -1;
+ }
+ printf("0x%x set to 0x%x\n", reg_addr, value);
+
+ return 0;
+}
+
+static void gpon_rx_status_usage(void) {
+ printf("gpon_rx_status\n");
+ printf("read Marvell 88F6601 GPON RX status registers\n");
+ printf("Example:\n");
+ printf("gpon_rx_status\n");
+}
+
+int gpon_rx_status(int argc, char *argv[]) {
+ unsigned int fec0, fec1, fec2, frame_cnt;
+
+ if (argc != 1 || argv == NULL) {
+ gpon_rx_status_usage();
+ return -1;
+ }
+
+ if (read_physical_addr(GPON_RECV_STATUS_FEC0, &fec0) != 0) {
+ printf("Read address 0x%x failed\n", GPON_RECV_STATUS_FEC0);
+ return -1;
+ }
+ if (read_physical_addr(GPON_RECV_STATUS_FEC1, &fec1) != 0) {
+ printf("Read address 0x%x failed\n", GPON_RECV_STATUS_FEC1);
+ return -1;
+ }
+ if (read_physical_addr(GPON_RECV_STATUS_FEC2, &fec2) != 0) {
+ printf("Read address 0x%x failed\n", GPON_RECV_STATUS_FEC2);
+ return -1;
+ }
+ if (read_physical_addr(GPON_RECV_STATUS_SUPER_FRAME_CNT, &frame_cnt) != 0) {
+ printf("Read address 0x%x failed\n", GPON_RECV_STATUS_SUPER_FRAME_CNT);
+ return -1;
+ }
+ printf(
+ "Bytes Received: 0x%x COR: 0x%x RX words Received: 0x%x Frame CNT: "
+ "0x%x\n",
+ fec0, fec1, fec2, frame_cnt);
+
+ return 0;
+}
+
+static void rx_prbs_cnt_usage(void) {
+ printf("rx_prbs_cnt\n");
+ printf("read Marvell 88F6601 RX PRBS coutner registers\n");
+ printf("Example:\n");
+ printf("rx_prbs_cnt\n");
+}
+
+int rx_prbs_cnt(int argc, char *argv[]) {
+ unsigned int cnt0, cnt1, cnt2;
+
+ if (argc != 1 || argv == NULL) {
+ rx_prbs_cnt_usage();
+ return -1;
+ }
+
+ if (set_pon_phy_out_of_reset() != 0) {
+ printf("Failed to take PHY out of reset\n");
+ return -1;
+ }
+ if (read_physical_addr(PON_PHY_TEST_PRBS_COUNTER_0, &cnt0) != 0) {
+ printf("Read address 0x%x failed\n", PON_PHY_TEST_PRBS_COUNTER_0);
+ return -1;
+ }
+ if (read_physical_addr(PON_PHY_TEST_PRBS_COUNTER_1, &cnt1) != 0) {
+ printf("Read address 0x%x failed\n", PON_PHY_TEST_PRBS_COUNTER_0);
+ return -1;
+ }
+ if (read_physical_addr(PON_PHY_TEST_PRBS_COUNTER_2, &cnt2) != 0) {
+ printf("Read address 0x%x failed\n", PON_PHY_TEST_PRBS_COUNTER_0);
+ return -1;
+ }
+ printf("RX PRBS count: 0x%x%04x%04x\n", cnt0, cnt1, cnt2);
+
+ return 0;
+}
+
+static void rx_prbs_err_cnt_usage(void) {
+ printf("rx_prbs_err_cnt\n");
+ printf("read Marvell 88F6601 RX PRBS error coutner registers\n");
+ printf("Example:\n");
+ printf("rx_prbs_err_cnt\n");
+}
+
+int rx_prbs_err_cnt(int argc, char *argv[]) {
+ unsigned int cnt0, cnt1;
+
+ if (argc != 1 || argv == NULL) {
+ rx_prbs_err_cnt_usage();
+ return -1;
+ }
+
+ if (set_pon_phy_out_of_reset() != 0) {
+ printf("Failed to take PHY out of reset\n");
+ return -1;
+ }
+ if (read_physical_addr(PON_PHY_TEST_PRBS_ERROR_COUNTER_0, &cnt0) != 0) {
+ printf("Read address 0x%x failed\n", PON_PHY_TEST_PRBS_ERROR_COUNTER_0);
+ return -1;
+ }
+ if (read_physical_addr(PON_PHY_TEST_PRBS_ERROR_COUNTER_0, &cnt1) != 0) {
+ printf("Read address 0x%x failed\n", PON_PHY_TEST_PRBS_ERROR_COUNTER_0);
+ return -1;
+ }
+ printf("RX PRBS error count: 0x%x%04x\n", cnt0, cnt1);
+
+ return 0;
+}
+
+static void gpon_cnts_usage(void) {
+ printf("gpon_cnts\n");
+ printf("dump all of Marvell 88F6601 GPON related error coutner registers\n");
+ printf("Example:\n");
+ printf("gpon_cnts\n");
+}
+
+int gpon_cnts(int argc, char *argv[]) {
+ if (argc != 1 || argv == NULL) {
+ gpon_cnts_usage();
+ return -1;
+ }
+
+ system_cmd("cat /sys/devices/platform/gpon/pm/bwMapCnt");
+ system_cmd("cat /sys/devices/platform/gpon/pm/fecCnt");
+ system_cmd("cat /sys/devices/platform/gpon/pm/gemCnt");
+ system_cmd("cat /sys/devices/platform/gpon/pm/rxPloamCnt");
+ system_cmd("cat /sys/devices/platform/gpon/pm/stdCnt");
+ system_cmd("cat /sys/devices/platform/gpon/pm/txPktCnt");
+ system_cmd("cat /sys/devices/platform/gpon/pm/txPloamCnt");
+
+ return 0;
+}
+
+static void gpon_alarms_usage(void) {
+ printf("gpon_alarms\n");
+ printf("Show 88F6601 GPON alarms\n");
+ printf("Example:\n");
+ printf("gpon_alarms\n");
+}
+
+int gpon_alarms(int argc, char *argv[]) {
+ if (argc != 1 || argv == NULL) {
+ gpon_alarms_usage();
+ return -1;
+ }
+
+ system_cmd("cat /sys/devices/platform/gpon/info/alarmGpon");
+
+ return 0;
+}
diff --git a/diags/chameleon/devmem3 b/diags/chameleon/devmem3
new file mode 100644
index 0000000..119b8b7
--- /dev/null
+++ b/diags/chameleon/devmem3
Binary files differ
diff --git a/diags/chameleon/diagutil.c b/diags/chameleon/diagutil.c
new file mode 100644
index 0000000..b2768d4
--- /dev/null
+++ b/diags/chameleon/diagutil.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2015 Google Inc.
+ * All rights reserved.
+ * diagutil -- Linux-based Hardware Diagnostic Utilities
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define DIAGS_VERSION "1.1"
+
+/* External Functions */
+int ioread(int argc, char **argv);
+int iowrite(int argc, char **argv);
+int iowrite_only(int argc, char *argv[]);
+int i2cread(int argc, char *argv[]);
+int i2cwrite(int argc, char *argv[]);
+int i2cprobe(int argc, char *argv[]);
+int gpio_stat(int argc, char *argv[]);
+int gpio_set_dir(int argc, char *argv[]);
+int gpio_set_out_val(int argc, char *argv[]);
+int gpio_set_tx_enable(int argc, char *argv[]);
+int gpio_mailbox(int argc, char *argv[]);
+int get_temp(int argc, char *argv[]);
+int set_leds(int argc, char *argv[]);
+int get_leds(int argc, char *argv[]);
+int phy_read(int argc, char *argv[]);
+int phy_write(int argc, char *argv[]);
+int loopback_test(int argc, char *argv[]);
+int phy_read(int argc, char *argv[]);
+int phy_write(int argc, char *argv[]);
+int soc_reg_read(int argc, char *argv[]);
+int soc_reg_write(int argc, char *argv[]);
+int gpon_rx_status(int argc, char *argv[]);
+int rx_prbs_cnt(int argc, char *argv[]);
+int rx_prbs_err_cnt(int argc, char *argv[]);
+int gpon_cnts(int argc, char *argv[]);
+int gpon_alarms(int argc, char *argv[]);
+int sfp_reg_read(int argc, char *argv[]);
+int sfp_reg_write(int argc, char *argv[]);
+int sfp_diags_reg_read(int argc, char *argv[]);
+int sfp_diags_reg_write(int argc, char *argv[]);
+int sfp_info(int argc, char *argv[]);
+int sfp_vendor(int argc, char *argv[]);
+int sfp_pn(int argc, char *argv[]);
+int sfp_wavelength(int argc, char *argv[]);
+int sfp_set_wavelength(int argc, char *argv[]);
+int sfp_set_pw(int argc, char *argv[]);
+
+/* Define the command structure */
+typedef struct {
+ const char *name;
+ int (*funcp)(int, char **);
+} tCOMMAND;
+
+void printVersion() { printf("%s\n", DIAGS_VERSION); }
+
+int version(int argc, char *argv[]) {
+ // This is to avoid unused params warning
+ if ((argc != 1) || (argv[0] == NULL)) {
+ printf("Invalid command parameter\n");
+ }
+ printVersion();
+ return 0;
+}
+
+/* Table of supported commands */
+tCOMMAND command_list[] = {
+ {"ioread", ioread},
+ {"iowrite", iowrite},
+ {"iowrite_only", iowrite_only},
+ {"", NULL},
+ {"i2cread", i2cread},
+ {"i2cwrite", i2cwrite},
+ {"i2cprobe", i2cprobe},
+ {"", NULL},
+ {"gpio_stat", gpio_stat},
+ {"gpio_set_dir", gpio_set_dir},
+ {"gpio_set_out_val", gpio_set_out_val},
+ {"gpio_set_tx_enable", gpio_set_tx_enable},
+ {"gpio_mailbox", gpio_mailbox},
+ {"get_temp", get_temp},
+ {"set_leds", set_leds},
+ {"get_leds", get_leds},
+ {"", NULL},
+ {"phy_read", phy_read},
+ {"phy_write", phy_write},
+ {"loopback_test", loopback_test},
+ {"", NULL},
+ {"soc_reg_read", soc_reg_read},
+ {"soc_reg_write", soc_reg_write},
+ {"gpon_rx_status", gpon_rx_status},
+ {"rx_prbs_cnt", rx_prbs_cnt},
+ {"rx_prbs_err_cnt", rx_prbs_err_cnt},
+ {"gpon_cnts", gpon_cnts},
+ {"gpon_alarms", gpon_alarms},
+ {"", NULL},
+ {"sfp_reg_read", sfp_reg_read},
+ {"sfp_reg_write", sfp_reg_write},
+ {"sfp_diags_reg_read", sfp_diags_reg_read},
+ {"sfp_diags_reg_write", sfp_diags_reg_write},
+ {"sfp_info", sfp_info},
+ {"sfp_vendor", sfp_vendor},
+ {"sfp_pn", sfp_pn},
+ {"sfp_wavelength", sfp_wavelength},
+ {"sfp_set_wavelength", sfp_set_wavelength},
+ {"sfp_set_pw", sfp_set_pw},
+ {"", NULL},
+ {"version", version},
+ {"", NULL},
+ {NULL, NULL},
+};
+
+static void usage(void) {
+ int i;
+
+ printf("Supported commands:\n");
+
+ for (i = 0; command_list[i].name != NULL; ++i) {
+ printf("\t%s\n", command_list[i].name);
+ }
+
+ return;
+}
+
+int main(int argc, char *argv[]) {
+ int i;
+
+ if (argc > 1) {
+ /* Search the command list for a match */
+ for (i = 0; command_list[i].name != NULL; ++i) {
+ if (strcmp(argv[1], command_list[i].name) == 0) {
+ return command_list[i].funcp(argc - 1, &argv[1]);
+ }
+ }
+ }
+
+ /* no command or bad command */
+ usage();
+
+ return 0;
+}
diff --git a/diags/chameleon/eth_test.c b/diags/chameleon/eth_test.c
new file mode 100644
index 0000000..734fc94
--- /dev/null
+++ b/diags/chameleon/eth_test.c
@@ -0,0 +1,538 @@
+/*
+ * (C) Copyright 2015 Google, Inc.
+ * All rights reserved.
+ *
+ */
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <linux/if_packet.h>
+#include <linux/types.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <netinet/ether.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "../common/io.h"
+#include "../common/util.h"
+#include "common.h"
+#include "mdio.h"
+
+#define ETH_PORT_NAME "eth0"
+#define MAX_NET_IF 2
+#define BUF_SIZ 1536
+#define ETH_TEST_MAX_CMD 4096
+#define ETH_TEST_MAX_RSP 4096
+#define ETH_TRAFFIC_PORT "wan0"
+#define ETH_TRAFFIC_REPORT_PERIOD 60
+#define ETH_TRAFFIC_MAX_REPORT_PERIOD 300
+#define ETH_TRAFFIC_TEST_PERIOD_SYMBOL "-p"
+// 100 Mb/s
+#define ETH_TRAFFIC_PER_PERIOD_MAX \
+ (((unsigned int)ETH_TRAFFIC_MAX_REPORT_PERIOD) * ((unsigned int)13107200))
+
+#define SERVER_PORT 8888
+#define MAX_CMD_SIZE 256
+#define SCAN_CMD_FORMAT "%256s"
+#define MAX_INT 0x7FFFFFFF
+
+#define ETH_SEND_DELAY_IN_USEC 1000
+#define ETH_MAX_LAN_PORTS 2
+#define ETH_WAIT_AFTER_LOOPBACK_SET 5
+#define ETH_PKTS_SENT_BEFORE_WAIT 0xFF
+#define ETH_PKTS_LEN_DEFAULT 128
+#define ETH_BUFFER_SIZE (ETH_PKTS_SENT_BEFORE_WAIT * ETH_PKTS_LEN_DEFAULT)
+#define ETH_LOOPBACK_PASS_FACTOR 0.8 // 80%
+#define ETH_TEST_FLUSH_NUM 5
+
+#define ETH_RX_NAME "RX"
+#define ETH_TX_NAME "TX"
+#define ETH_PACKETS_NAME "packets:"
+#define ETH_ERRORS_NAME "errors:"
+#define ETH_BYTES_NAME "bytes:"
+#define ONE_MEG (1024 * 1024)
+
+#define ETH_DEBUG_PORT_ADDR_REG 0x1D
+#define ETH_DEBUG_PORT_DATA_REG 0x1E
+#define ETH_EXT_LPBK_PORT_ADDR_OFFSET 0xB
+#define ETH_EXT_LPBK_PORT_SET_DATA 0x3C40
+#define ETH_EXT_LPBK_PORT_CLEAR_DATA 0xBC00
+#define ETH_STAT_CLEAR_CMD "ifstat > /dev/null"
+#define ETH_STAT_CMD "ifstat %s | sed '1,3d;5d'"
+#define ETH_STAT_RX_POS 5
+#define ETH_STAT_TX_POS 7
+#define ETH_STAT_WAIT_PERIOD 1 // sec
+#define ETH_STAT_PERCENT_MARGIN 95
+
+#define ETH0_SMI_REG 0xF1072004
+
+void send_mac_pkt(char *if_name, char *out_name, unsigned int xfer_len,
+ unsigned int xfer_wait, int n,
+ const unsigned char *dst_mac1) {
+ int sockfd, i;
+ struct ifreq if_idx;
+ struct ifreq if_mac, out_mac;
+ int tx_len = 0;
+ char sendbuf[BUF_SIZ];
+ struct ether_header *eh = (struct ether_header *)sendbuf;
+ struct sockaddr_ll socket_address;
+ unsigned char dst_mac[6] = {0, 0, 0, 0, 0, 0};
+
+ /* Open RAW socket to send on */
+ if ((sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)) == -1) {
+ perror("socket");
+ }
+
+ /* Get the index of the interface to send on */
+ memset(&if_idx, 0, sizeof(if_idx));
+ safe_strncpy(if_idx.ifr_name, if_name, IFNAMSIZ - 1);
+ if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0) {
+ perror("SIOCGIFINDEX");
+ }
+ /* Get the MAC address of the interface to send on */
+ memset(&out_mac, 0, sizeof(out_mac));
+ if (out_name != NULL) {
+ safe_strncpy(out_mac.ifr_name, out_name, IFNAMSIZ - 1);
+ if (ioctl(sockfd, SIOCGIFHWADDR, &out_mac) < 0) {
+ perror("out SIOCGIFHWADDR");
+ }
+ }
+ memset(&if_mac, 0, sizeof(if_mac));
+ safe_strncpy(if_mac.ifr_name, if_name, IFNAMSIZ - 1);
+ if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0) {
+ perror("SIOCGIFHWADDR");
+ }
+ if (out_name != NULL) {
+ dst_mac[0] = ((uint8_t *)&out_mac.ifr_hwaddr.sa_data)[0];
+ dst_mac[1] = ((uint8_t *)&out_mac.ifr_hwaddr.sa_data)[1];
+ dst_mac[2] = ((uint8_t *)&out_mac.ifr_hwaddr.sa_data)[2];
+ dst_mac[3] = ((uint8_t *)&out_mac.ifr_hwaddr.sa_data)[3];
+ dst_mac[4] = ((uint8_t *)&out_mac.ifr_hwaddr.sa_data)[4];
+ dst_mac[5] = ((uint8_t *)&out_mac.ifr_hwaddr.sa_data)[5];
+ } else if (dst_mac1 != NULL) {
+ dst_mac[0] = dst_mac1[0];
+ dst_mac[1] = dst_mac1[1];
+ dst_mac[2] = dst_mac1[2];
+ dst_mac[3] = dst_mac1[3];
+ dst_mac[4] = dst_mac1[4];
+ dst_mac[5] = dst_mac1[5];
+ } else {
+ printf("Invalid out_name and dst_mac.\n");
+ return;
+ }
+
+ /* Construct the Ethernet header */
+ // memset(sendbuf, 0, BUF_SIZ);
+ for (i = 0; i < BUF_SIZ; ++i) {
+ sendbuf[i] = 0xA5;
+ }
+ /* Ethernet header */
+ eh->ether_shost[0] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[0];
+ eh->ether_shost[1] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[1];
+ eh->ether_shost[2] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[2];
+ eh->ether_shost[3] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[3];
+ eh->ether_shost[4] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[4];
+ eh->ether_shost[5] = ((uint8_t *)&if_mac.ifr_hwaddr.sa_data)[5];
+ eh->ether_dhost[0] = dst_mac[0];
+ eh->ether_dhost[1] = dst_mac[1];
+ eh->ether_dhost[2] = dst_mac[2];
+ eh->ether_dhost[3] = dst_mac[3];
+ eh->ether_dhost[4] = dst_mac[4];
+ eh->ether_dhost[5] = dst_mac[5];
+ /* Ethertype field */
+ eh->ether_type = htons(ETH_P_IP);
+ tx_len += sizeof(struct ether_header);
+
+ /* Packet data */
+ sendbuf[tx_len++] = 0xde;
+ sendbuf[tx_len++] = 0xad;
+ sendbuf[tx_len++] = 0xbe;
+ sendbuf[tx_len++] = 0xef;
+
+ /* Index of the network device */
+ socket_address.sll_ifindex = if_idx.ifr_ifindex;
+ /* Address length*/
+ socket_address.sll_halen = ETH_ALEN;
+ /* Destination MAC */
+ socket_address.sll_addr[0] = dst_mac[0];
+ socket_address.sll_addr[1] = dst_mac[1];
+ socket_address.sll_addr[2] = dst_mac[2];
+ socket_address.sll_addr[3] = dst_mac[3];
+ socket_address.sll_addr[4] = dst_mac[4];
+ socket_address.sll_addr[5] = dst_mac[5];
+
+ /* Send packet */
+ if (n < 0) {
+ while (1) {
+ if (sendto(sockfd, sendbuf, xfer_len, 0,
+ (struct sockaddr *)&socket_address,
+ sizeof(struct sockaddr_ll)) < 0) {
+ printf("Send failed at msg %d\n", i);
+ break;
+ }
+ if (xfer_wait > 0) {
+ if ((i & ETH_PKTS_SENT_BEFORE_WAIT) == 0) {
+ usleep(xfer_wait);
+ }
+ }
+ }
+ } else {
+ for (i = 0; i < n; ++i) {
+ if (sendto(sockfd, sendbuf, xfer_len, 0,
+ (struct sockaddr *)&socket_address,
+ sizeof(struct sockaddr_ll)) < 0) {
+ printf("Send failed at msg %d\n", i);
+ break;
+ }
+ if (xfer_wait > 0) {
+ if ((i & ETH_PKTS_SENT_BEFORE_WAIT) == 0) {
+ usleep(xfer_wait);
+ }
+ }
+ }
+ }
+ close(sockfd);
+}
+
+/* If extra is not NULL, rsp is returned as the string followed extra */
+int scan_command(char *command, char *rsp, char *extra) {
+ FILE *fp;
+ fp = popen(command, "r");
+ if (fp != NULL) {
+ if (extra != NULL) {
+ while (fscanf(fp, "%s", rsp) != EOF) {
+ if (!strcmp(rsp, extra)) {
+ if (fscanf(fp, "%s", rsp) <= 0)
+ return -1;
+ else
+ return 0;
+ }
+ }
+ } else {
+ fscanf(fp, SCAN_CMD_FORMAT, rsp);
+ }
+ pclose(fp);
+ } else {
+ return -1;
+ }
+ return 0;
+}
+
+int net_stat(unsigned int *rx_bytes, unsigned int *tx_bytes, char *name) {
+ static unsigned int tx_stat = 0;
+ static unsigned int rx_stat = 0;
+ char command[MAX_CMD_SIZE], rsp[MAX_CMD_SIZE];
+ unsigned int tmp;
+
+ if (strcmp(name, ETH_PORT_NAME) != 0) {
+ return -1;
+ }
+
+ snprintf(command, sizeof(command),
+ "cat /sys/class/net/%s/statistics/tx_bytes", name);
+ if (scan_command(command, rsp, NULL) == 0) *tx_bytes = strtoul(rsp, NULL, 10);
+
+ snprintf(command, sizeof(command),
+ "cat /sys/class/net/%s/statistics/rx_bytes", name);
+ if (scan_command(command, rsp, NULL) == 0) *rx_bytes = strtoul(rsp, NULL, 10);
+
+ if (*tx_bytes >= tx_stat) {
+ *tx_bytes -= tx_stat;
+ tx_stat += *tx_bytes;
+ } else {
+ tmp = *tx_bytes;
+ // tx_bytes is uint. It will continue to increment till wrap around
+ // When it wraps around, the current value will be less than the
+ // previous one. That is why this logic kicked in.
+ *tx_bytes += (0xffffffff - tx_stat);
+ tx_stat = tmp;
+ }
+
+ if (*rx_bytes >= rx_stat) {
+ *rx_bytes -= rx_stat;
+ rx_stat += *rx_bytes;
+ } else {
+ tmp = *rx_bytes;
+ // rx_bytes is uint. It will continue to increment till wrap around
+ // When it wraps around, the current value will be less than the
+ // previous one. That is why this logic kicked in.
+ *rx_bytes += (0xffffffff - rx_stat);
+ rx_stat = tmp;
+ }
+ return 0;
+}
+
+// Return 0 if lost carrier. Otherwise, 1
+int get_carrier_state(char *name) {
+ char command[MAX_CMD_SIZE], rsp[MAX_CMD_SIZE];
+
+ snprintf(command, sizeof(command), "cat /sys/class/net/%s/carrier", name);
+ if (scan_command(command, rsp, NULL) == 0) {
+ if (strcmp(rsp, "0") != 0) return 1;
+ }
+ return 0;
+}
+
+// This is the same as sleep but monitor the link carrier every second
+// Return true if the carrier is good every second. Otherwise false
+bool sleep_and_check_carrier(int duration, char *if_name) {
+ bool good_carrier = true;
+ int i;
+ for (i = 0; i < duration; ++i) {
+ if (get_carrier_state(if_name) == 0) good_carrier = false;
+ sleep(1);
+ }
+ return good_carrier;
+}
+
+int get_if_ip(char *name, unsigned int *ip) {
+ char command[ETH_TEST_MAX_CMD], rsp[ETH_TEST_MAX_RSP];
+ bool found = false;
+
+ snprintf(command, sizeof(command), "ip addr show %s", name);
+ if (scan_command(command, rsp, "inet") == 0) {
+ if (sscanf(rsp, "%u.%u.%u.%u", ip, (ip + 1), (ip + 2), (ip + 3)) <= 0) {
+ return -1;
+ }
+ found = true;
+ }
+
+ if (!found) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static void phy_read_usage(void) {
+ printf("phy_read <ifname> <reg>\n");
+ printf("Example:\n");
+ printf("phy_read %s 2\n", ETH_PORT_NAME);
+}
+
+int phy_read(int argc, char *argv[]) {
+ int rc = 0;
+ unsigned int tmp, reg, val = 0;
+
+ if (argc != 3) {
+ phy_read_usage();
+ return -1;
+ }
+
+ if (strcmp(argv[1], ETH_PORT_NAME) != 0) {
+ printf("Currently support only port %s\n", ETH_PORT_NAME);
+ return -1;
+ }
+
+ reg = strtol(argv[2], NULL, 0);
+ tmp = reg;
+ reg = (reg << 21) + (1 << 26);
+ rc = write_physical_addr(ETH0_SMI_REG, reg);
+ rc += read_physical_addr(ETH0_SMI_REG, &val);
+ val &= 0xFFFF;
+ printf("PHY %s Reg 0x%x is 0x%x\n", argv[1], tmp, val);
+ return 0;
+}
+
+static void phy_write_usage(void) {
+ printf("phy_write <ifname> <reg> <val>\n");
+ printf("Example:\n");
+ printf("phy_write i%s 22 0x6\n", ETH_PORT_NAME);
+}
+
+int phy_write(int argc, char *argv[]) {
+ int rc = 0;
+ int tmp, reg, val;
+
+ if (argc != 4) {
+ phy_write_usage();
+ return -1;
+ }
+
+ if (strcmp(argv[1], ETH_PORT_NAME) != 0) {
+ printf("Currently support only port %s\n", ETH_PORT_NAME);
+ return -1;
+ }
+
+ reg = strtol(argv[2], NULL, 0);
+ tmp = reg;
+ val = strtol(argv[3], NULL, 16);
+ reg = (reg << 21) + (0 << 26);
+ val &= 0xFFFF;
+ rc = write_physical_addr(ETH0_SMI_REG, reg);
+ rc += write_physical_addr(ETH0_SMI_REG, (reg + val));
+ printf("PHY %s Reg 0x%x = 0x%x\n", argv[1], tmp, val);
+ return 0;
+}
+
+static void send_if_usage(void) {
+ printf("send_if <source if> <num> [-t <delay between pkts send>]\n");
+ printf("Example:\n");
+ printf("send_if lan0 100\n");
+ printf("send 100 msg out of lan0\n");
+}
+
+int send_if(int argc, char *argv[]) {
+ int n;
+ char if_name[IFNAMSIZ];
+ unsigned int xfer_wait = ETH_SEND_DELAY_IN_USEC;
+ unsigned char dst_mac[6] = {0, 0, 0, 0, 0, 0};
+
+ /* Get interface name */
+ if (argc == 5) {
+ if (strcmp(argv[3], "-t") == 0) {
+ xfer_wait = strtoul(argv[4], NULL, 10);
+ } else {
+ send_if_usage();
+ return -1;
+ }
+ } else if (argc != 3) {
+ send_if_usage();
+ return -1;
+ }
+
+ strcpy(if_name, argv[1]);
+ n = strtol(argv[2], NULL, 10);
+
+ send_mac_pkt(if_name, NULL, BUF_SIZ, xfer_wait, n, dst_mac);
+
+ printf("Sent %d pkt of size %d from %s to %s\n", n, BUF_SIZ, argv[1],
+ argv[2]);
+
+ return 0;
+}
+
+static void loopback_test_usage(void) {
+ printf(
+ "loopback_test <interface> <duration in secs> "
+ "[<%s print-period in secs>]\n",
+ ETH_TRAFFIC_TEST_PERIOD_SYMBOL);
+ printf("- duration >=1 or -1 (forever)\n");
+ printf("- print-period >= 0 and <= %d\n", ETH_TRAFFIC_MAX_REPORT_PERIOD);
+ printf("- print-period > 0 if duration > 0\n");
+ printf("- print-period = 0 prints only the summary\n");
+}
+
+int loopback_test(int argc, char *argv[]) {
+ int duration, num = -1, collected_count = 0;
+ int pid, pid1, print_period = ETH_TRAFFIC_REPORT_PERIOD;
+ unsigned int pkt_len = ETH_PKTS_LEN_DEFAULT, rx_bytes, tx_bytes;
+ bool print_every_period = true, traffic_problem = false, problem = false;
+ float average_throughput = 0.0, throughput;
+ unsigned char dst_mac[6] = {0, 0, 0, 0, 0, 0};
+
+ if ((argc != 3) && (argc != 5)) {
+ loopback_test_usage();
+ return -1;
+ }
+
+ if (strcmp(argv[1], ETH_PORT_NAME) != 0) {
+ printf("Invalid Ethernet Interface %s\n", argv[1]);
+ return -1;
+ }
+
+ duration = strtol(argv[2], NULL, 0);
+ if ((duration < -1) || (duration == 0)) {
+ loopback_test_usage();
+ return -1;
+ }
+
+ if (argc == 5) {
+ if (strcmp(argv[3], ETH_TRAFFIC_TEST_PERIOD_SYMBOL) != 0) {
+ loopback_test_usage();
+ return -1;
+ }
+
+ print_period = strtoul(argv[4], NULL, 0);
+ if (((print_period == 0) && (duration < 0)) || (print_period < 0) ||
+ (print_period > ETH_TRAFFIC_MAX_REPORT_PERIOD)) {
+ loopback_test_usage();
+ return -1;
+ }
+ if (print_period == 0) {
+ print_every_period = false;
+ print_period = ETH_TRAFFIC_REPORT_PERIOD;
+ }
+ }
+
+ // eth_external_loopback(argv[1], true);
+ system_cmd("ethtool -s " ETH_PORT_NAME " autoneg off duplex full speed 100");
+ sleep(2);
+
+ net_stat(&rx_bytes, &tx_bytes, argv[1]);
+
+ pid = fork();
+ if (pid < 0) {
+ printf("Server fork error %d, errno %d\n", pid, errno);
+ return -1;
+ }
+ if (pid == 0) {
+ // Child process
+ send_mac_pkt(argv[1], NULL, pkt_len, 0, num, dst_mac);
+ exit(0);
+ }
+ // Parent process
+ pid1 = pid;
+
+ while (duration != 0) {
+ if (duration >= 0) {
+ if (duration <= print_period) {
+ problem = !sleep_and_check_carrier(duration, argv[1]);
+ print_period = duration;
+ duration = 0;
+ kill(pid1, SIGKILL);
+ // printf("Killed processes %d and %d\n", pid1, pid2);
+ } else {
+ duration -= print_period;
+ problem = !sleep_and_check_carrier(print_period, argv[1]);
+ }
+ } else {
+ problem = !sleep_and_check_carrier(print_period, argv[1]);
+ }
+
+ if (duration > 0) kill(pid1, SIGSTOP);
+ sleep(ETH_STAT_WAIT_PERIOD);
+ net_stat(&rx_bytes, &tx_bytes, argv[1]);
+ if (duration > 0) kill(pid1, SIGCONT);
+ ++collected_count;
+ // Give 1% margin
+ if ((rx_bytes == 0) ||
+ (((tx_bytes / 100) * ETH_STAT_PERCENT_MARGIN) > rx_bytes)) {
+ problem = true;
+ }
+ if ((rx_bytes > ETH_TRAFFIC_PER_PERIOD_MAX) ||
+ (tx_bytes > ETH_TRAFFIC_PER_PERIOD_MAX)) {
+ problem = true;
+ }
+ traffic_problem |= problem;
+ if (!problem) {
+ throughput = (((float)rx_bytes) * 8) / (float)(print_period * ONE_MEG);
+ average_throughput += throughput;
+ } else {
+ throughput = 0.0;
+ }
+ if (print_every_period) {
+ printf("%s %s: %3.3f Mb/s (%d:%d)\n", (problem) ? FAIL_TEXT : PASS_TEXT,
+ argv[1], throughput, tx_bytes, rx_bytes);
+ }
+ problem = false;
+ }
+
+ // eth_external_loopback(argv[1], false);
+ system_cmd("ethtool -s " ETH_PORT_NAME " autoneg on");
+
+ average_throughput /= ((float)collected_count);
+ printf("%s overall %s: %3.3f Mb/s\n",
+ (traffic_problem) ? FAIL_TEXT : PASS_TEXT, argv[1],
+ average_throughput);
+
+ return 0;
+}
diff --git a/diags/chameleon/gpio.c b/diags/chameleon/gpio.c
new file mode 100644
index 0000000..0ec2bd2
--- /dev/null
+++ b/diags/chameleon/gpio.c
@@ -0,0 +1,407 @@
+/*
+ * (C) Copyright 2016 Google, Inc.
+ * All rights reserved.
+ *
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "../common/io.h"
+#include "../common/util.h"
+#include "i2c.h"
+
+#define STOP_STR "stop"
+#define START_STR "start"
+#define LINE_MAX 128
+#define GET_TEMP "cat /sys/devices/platform/KW2Thermal.0/temp1_input"
+#define RED_LED "red"
+#define RED_LED_BRIGHTNESS "/sys/class/leds/sys-red/brightness"
+#define BLUE_LED "blue"
+#define BLUE_LED_BRIGHTNESS "/sys/class/leds/sys-blue/brightness"
+#define MPP_CONTROL_REG 0x00018000
+#define GPIO_DATA_OUT_REG 0x00018100
+#define GPIO_DATA_OUT_EN_REG 0x00018104
+#define GPIO_DATA_IN_REG 0x00018110
+#define GPIO_HIGH_DATA_OUT_REG 0x00018124
+#define GPIO_HIGH_DATA_OUT_EN_REG 0x00018128
+#define GPIO_HIGH_DATA_IN_REG 0x00018134
+#define GPIO_HIGH_PIN_START_NUM 32
+#define GPIO_MAX_PIN_NUM 37
+#define GPIO_DIR_IN_STR "in"
+#define GPIO_DIR_OUT_STR "out"
+#define GPIO_21_PON_TX_DIS 21
+#define AVANTA_BASE_ADDR 0xF1000000
+
+#define BOARD_TEMP_BUS 0
+#define BOARD_TEMP_ADDR 0x48
+#define BOARD_TEMP_ADDR_LEN 1
+#define BOARD_TEMP_REG 0
+#define BOARD_TEMP_LEN 2
+
+static void gpio_set_tx_enable_usage(void) {
+ printf("gpio_set_tx_enable <0 | 1>\n");
+ printf("Example:\n");
+ printf("gpio_set_tx_enable 0\n");
+ printf("set TX_ENABLE pin to low\n");
+}
+
+int gpio_set_tx_enable(int argc, char *argv[]) {
+ unsigned int tx_en_val, out_en, out, mask = 1 << GPIO_21_PON_TX_DIS;
+ unsigned int out_en_reg = AVANTA_BASE_ADDR + GPIO_DATA_OUT_EN_REG;
+ unsigned int out_reg = AVANTA_BASE_ADDR + GPIO_DATA_OUT_REG;
+ unsigned int mpp_ctrl =
+ AVANTA_BASE_ADDR + MPP_CONTROL_REG + (4 * (GPIO_21_PON_TX_DIS / 8));
+
+ if (argc != 2) {
+ gpio_set_tx_enable_usage();
+ return -1;
+ }
+ tx_en_val = get_num(argv[1]);
+ if (tx_en_val != 0 && tx_en_val != 1) {
+ printf("Invalid TX_ENABLE value %d\n", tx_en_val);
+ gpio_set_tx_enable_usage();
+ return -1;
+ }
+ if (read_physical_addr(out_en_reg, &out_en) != 0) {
+ printf("Read address 0x%x failed\n", out_en_reg);
+ return -1;
+ }
+ if ((out_en & mask) != 0) {
+ out_en &= ~mask;
+ if (write_physical_addr(out_en_reg, out_en) != 0) {
+ printf("Write address 0x%x of value 0x%x failed\n", out_en_reg, out_en);
+ return -1;
+ }
+ }
+ if (read_physical_addr(out_reg, &out) != 0) {
+ printf("Read address 0x%x failed\n", out_reg);
+ return -1;
+ }
+ if ((out & mask) != (tx_en_val << GPIO_21_PON_TX_DIS)) {
+ out = (out & (~mask)) | (tx_en_val << GPIO_21_PON_TX_DIS);
+ if (write_physical_addr(out_reg, out) != 0) {
+ printf("Write address 0x%x of value 0x%x failed\n", out_reg, out);
+ return -1;
+ }
+ }
+ // set MPP function to gpio
+ if (read_physical_addr(mpp_ctrl, &out) != 0) {
+ printf("Read address 0x%x failed\n", mpp_ctrl);
+ return -1;
+ }
+ out &= ~(0xFF << (4 * (GPIO_21_PON_TX_DIS % 8)));
+ if (write_physical_addr(mpp_ctrl, out) != 0) {
+ printf("Write address 0x%x of value 0x%x failed\n", mpp_ctrl, out);
+ return -1;
+ }
+ printf("Set TX_ENABLE to %d\n", tx_en_val);
+ return 0;
+}
+
+static void gpio_stat_usage(void) {
+ printf("gpio_stat <GPIO pin num (0 to %d)>\n", GPIO_MAX_PIN_NUM);
+ printf("Example:\n");
+ printf("gpio_stat 21\n");
+ printf("Display the status of the specified GPIO pin\n");
+}
+
+int gpio_stat(int argc, char *argv[]) {
+ unsigned int pin_num, pin_mask, in, out, out_en;
+ unsigned int out_reg, out_en_reg, in_reg;
+
+ if (argc != 2) {
+ gpio_stat_usage();
+ return -1;
+ }
+
+ pin_num = get_num(argv[1]);
+
+ if (pin_num > GPIO_MAX_PIN_NUM) {
+ printf("Invalid GPIO pin number %d\n", pin_num);
+ gpio_stat_usage();
+ return -1;
+ }
+ if (pin_num >= GPIO_HIGH_PIN_START_NUM) {
+ out_reg = AVANTA_BASE_ADDR + GPIO_HIGH_DATA_OUT_REG;
+ out_en_reg = AVANTA_BASE_ADDR + GPIO_HIGH_DATA_OUT_EN_REG;
+ in_reg = AVANTA_BASE_ADDR + GPIO_HIGH_DATA_IN_REG;
+ pin_mask = 1 << (pin_num - GPIO_HIGH_PIN_START_NUM);
+ } else {
+ out_reg = AVANTA_BASE_ADDR + GPIO_DATA_OUT_REG;
+ out_en_reg = AVANTA_BASE_ADDR + GPIO_DATA_OUT_EN_REG;
+ in_reg = AVANTA_BASE_ADDR + GPIO_DATA_IN_REG;
+ pin_mask = 1 << pin_num;
+ }
+ if (read_physical_addr(out_reg, &out) != 0) {
+ printf("Read address 0x%x failed\n", out_reg);
+ return -1;
+ }
+ if (read_physical_addr(out_en_reg, &out_en) != 0) {
+ printf("Read address 0x%x failed\n", out_en_reg);
+ return -1;
+ }
+ if (read_physical_addr(in_reg, &in) != 0) {
+ printf("Read address 0x%x failed\n", in_reg);
+ return -1;
+ }
+ printf("GPIO pin %d: DIR: %s IN: 0x%x OUT: 0x%x\n", pin_num,
+ (out_en & pin_mask) ? "in" : "out", (in & pin_mask) ? 1 : 0,
+ (out & pin_mask) ? 1 : 0);
+ printf("GPIO regs: EN 0x%08x OUT 0x%08x IN 0x%08x MASK 0x%08x\n", out_en, out,
+ in, pin_mask);
+
+ return 0;
+}
+
+static void gpio_set_dir_usage(void) {
+ printf("gpio_set_dir <GPIO pin num (0 to %d)> <%s | %s>\n", GPIO_MAX_PIN_NUM,
+ GPIO_DIR_IN_STR, GPIO_DIR_OUT_STR);
+ printf("Example:\n");
+ printf("gpio_set_dir 21 %s\n", GPIO_DIR_OUT_STR);
+ printf("set the specified GPIO pin to input or output\n");
+}
+
+int gpio_set_dir(int argc, char *argv[]) {
+ unsigned int pin_num, pin_mask, out_en, out_en_reg;
+ bool is_output = true;
+
+ if (argc != 3) {
+ gpio_set_dir_usage();
+ return -1;
+ }
+
+ pin_num = get_num(argv[1]);
+
+ if (pin_num > GPIO_MAX_PIN_NUM) {
+ printf("Invalid GPIO pin number %d\n", pin_num);
+ gpio_set_dir_usage();
+ return -1;
+ }
+
+ if (strcmp(argv[2], GPIO_DIR_IN_STR) == 0)
+ is_output = false;
+ else if (strcmp(argv[2], GPIO_DIR_OUT_STR) == 0)
+ is_output = true;
+ else {
+ printf("Invalid GPIO pin direction %s\n", argv[2]);
+ gpio_set_dir_usage();
+ return -1;
+ }
+
+ if (pin_num >= GPIO_HIGH_PIN_START_NUM) {
+ out_en_reg = AVANTA_BASE_ADDR + GPIO_HIGH_DATA_OUT_EN_REG;
+ pin_mask = 1 << (pin_num - GPIO_HIGH_PIN_START_NUM);
+ } else {
+ out_en_reg = AVANTA_BASE_ADDR + GPIO_DATA_OUT_EN_REG;
+ pin_mask = 1 << pin_num;
+ }
+ if (read_physical_addr(out_en_reg, &out_en) != 0) {
+ printf("Read address 0x%x failed\n", out_en_reg);
+ return -1;
+ }
+ if (is_output)
+ out_en &= ~pin_mask;
+ else
+ out_en |= pin_mask;
+ if (write_physical_addr(out_en_reg, out_en) != 0) {
+ printf("Write address 0x%x of value 0x%x failed\n", out_en_reg, out_en);
+ return -1;
+ }
+ printf("GPIO pin %d set as %s\n", pin_num, (is_output) ? "output" : "input");
+
+ return 0;
+}
+
+static void gpio_set_out_val_usage(void) {
+ printf("gpio_set_out_val <GPIO pin num (0 to %d)> <0 | 1>\n",
+ GPIO_MAX_PIN_NUM);
+ printf("Example:\n");
+ printf("gpio_set_out_val 21 0\n");
+ printf("set the specified GPIO pin output to 0\n");
+}
+
+int gpio_set_out_val(int argc, char *argv[]) {
+ unsigned int pin_num, pin_val, pin_mask, out, out_reg;
+
+ if (argc != 3) {
+ gpio_set_out_val_usage();
+ return -1;
+ }
+
+ pin_num = get_num(argv[1]);
+ pin_val = get_num(argv[2]);
+
+ if (pin_num > GPIO_MAX_PIN_NUM) {
+ printf("Invalid GPIO pin number %d\n", pin_num);
+ gpio_set_out_val_usage();
+ return -1;
+ }
+
+ if (pin_val != 0 && pin_val != 1) {
+ printf("Invalid GPIO pin value %d\n", pin_val);
+ gpio_set_out_val_usage();
+ return -1;
+ }
+
+ if (pin_num >= GPIO_HIGH_PIN_START_NUM) {
+ out_reg = AVANTA_BASE_ADDR + GPIO_HIGH_DATA_OUT_REG;
+ pin_mask = 1 << (pin_num - GPIO_HIGH_PIN_START_NUM);
+ } else {
+ out_reg = AVANTA_BASE_ADDR + GPIO_DATA_OUT_REG;
+ pin_mask = 1 << pin_num;
+ }
+ if (read_physical_addr(out_reg, &out) != 0) {
+ printf("Read address 0x%x failed\n", out_reg);
+ return -1;
+ }
+ if (pin_val)
+ out |= pin_mask;
+ else
+ out &= ~pin_mask;
+ if (write_physical_addr(out_reg, out) != 0) {
+ printf("Write address 0x%x of value 0x%x failed\n", out_reg, out);
+ return -1;
+ }
+ printf("GPIO pin %d output set as %d\n", pin_num, pin_val);
+
+ return 0;
+}
+
+static void gpio_mailbox_usage(void) {
+ printf("gpio_mailbox <%s | %s>\n", STOP_STR, START_STR);
+ printf("Example:\n");
+ printf("gpio_mailbox %s\n", STOP_STR);
+ printf("Stop gpio_mailbox from running\n");
+}
+
+int gpio_mailbox(int argc, char *argv[]) {
+ if (argc != 2) {
+ gpio_mailbox_usage();
+ return -1;
+ }
+
+ if (strcmp(argv[1], STOP_STR) == 0) {
+ system_cmd("pkill -9 -f gpio-mailbox");
+ } else if (strcmp(argv[1], START_STR) == 0) {
+ system_cmd("gpio-mailbox 2>&1 | logos gpio-mailbox &");
+ } else {
+ gpio_mailbox_usage();
+ return -1;
+ }
+
+ return 0;
+}
+
+static void get_temp_usage(void) {
+ printf("get_temp\n");
+ printf("display CPU temperature in mili-degree C\n");
+ printf("Example\n");
+ printf(" prism-diags get_temp\n");
+}
+
+int get_temp(int argc, char *argv[]) {
+ float temp;
+ int t;
+ uint8_t value[BOARD_TEMP_LEN];
+ FILE *fp;
+
+ if (argc != 1 || argv == NULL) {
+ get_temp_usage();
+ return -1;
+ }
+ if (i2cr(BOARD_TEMP_BUS, BOARD_TEMP_ADDR, BOARD_TEMP_REG, BOARD_TEMP_ADDR_LEN,
+ BOARD_TEMP_LEN, value) != 0) {
+ printf("Temp sensor read address 0x%x failed\n", BOARD_TEMP_ADDR);
+ return -1;
+ }
+ temp = (float)(value[0]) + (((float)(value[1])) / 256.0);
+ if (value[0] & 0x80) {
+ temp -= 256.0;
+ }
+ printf(" Board Temp: %3.3f\n", temp);
+ fp = popen(GET_TEMP, "r");
+ if (fp != NULL) {
+ if (fscanf(fp, "%d", &t) <= 0) {
+ printf("Failed to read CPU temp\n");
+ pclose(fp);
+ return -1;
+ }
+ pclose(fp);
+ temp = (float)t / 1000.0;
+ printf(" CPU Temp: %3.3f\n", temp);
+ } else {
+ printf("Failed to get CPU temp\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void set_leds_usage(void) {
+ printf("set_leds <%s | %s> <value>\n", RED_LED, BLUE_LED);
+ printf("set specified LED brightness to <valueue>\n");
+ printf(" max value is 100. set value to 0 to turn it off\n");
+ printf("Example\n");
+ printf(" prism-diags set_leds %s 10\n", RED_LED);
+}
+
+int set_leds(int argc, char *argv[]) {
+ int value;
+ char cmd[LINE_MAX];
+
+ if (argc != 3) {
+ set_leds_usage();
+ return -1;
+ }
+ value = strtol(argv[2], NULL, 10);
+
+ if (strcmp(argv[1], RED_LED) == 0) {
+ sprintf(cmd, "echo %d > %s", value, RED_LED_BRIGHTNESS);
+ } else if (strcmp(argv[1], BLUE_LED) == 0) {
+ sprintf(cmd, "echo %d > %s", value, BLUE_LED_BRIGHTNESS);
+ } else {
+ printf("Unknown LED\n");
+ set_leds_usage();
+ return -1;
+ }
+ system_cmd(cmd);
+ printf("Set %s LED brightness to %d\n", argv[1], value);
+
+ return 0;
+}
+
+static void get_leds_usage(void) {
+ printf("get_leds <%s | %s>\n", RED_LED, BLUE_LED);
+ printf("get specified LED brightness\n");
+ printf("Example\n");
+ printf(" prism-diags get_leds %s\n", RED_LED);
+}
+
+int get_leds(int argc, char *argv[]) {
+ char cmd[LINE_MAX];
+
+ if (argc != 2) {
+ get_leds_usage();
+ return -1;
+ }
+
+ if (strcmp(argv[1], RED_LED) == 0) {
+ sprintf(cmd, "cat %s", RED_LED_BRIGHTNESS);
+ } else if (strcmp(argv[1], BLUE_LED) == 0) {
+ sprintf(cmd, "cat %s", BLUE_LED_BRIGHTNESS);
+ } else {
+ printf("Unknown LED\n");
+ get_leds_usage();
+ return -1;
+ }
+ printf("%s LED brightness is ", argv[1]);
+ fflush(stdout);
+ system_cmd(cmd);
+
+ return 0;
+}
diff --git a/diags/chameleon/i2c.c b/diags/chameleon/i2c.c
new file mode 100644
index 0000000..1107bfc
--- /dev/null
+++ b/diags/chameleon/i2c.c
@@ -0,0 +1,163 @@
+/*
+ * (C) Copyright 2014 Google, Inc.
+ * All rights reserved.
+ *
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "i2c.h"
+
+extern int ioctl(int, int, void *);
+
+int i2cr(int controller, uint8_t device_addr, uint32_t cell_addr,
+ uint32_t addr_len, uint32_t data_len, uint8_t *buf) {
+ char filename[FILENAME_SIZE];
+ int file;
+ int i;
+ uint32_t temp;
+ unsigned char addrbuf[4]; /* up to 4 byte addressing ! */
+ int return_code = 0;
+ struct i2c_msg message[2];
+ struct i2c_rdwr_ioctl_data rdwr_arg;
+ unsigned int read_data_len;
+
+ /* open the I2C adapter */
+ snprintf(filename, sizeof(filename), I2C_DEV_FILE, controller);
+ if ((file = open(filename, O_RDWR)) < 0) {
+ printf("I2C Error open file %s: %s", filename, strerror(errno));
+ return -1;
+ }
+
+ if ((return_code = flock(file, LOCK_EX)) < 0) {
+ printf("I2C Error lock file %s: %s", filename, strerror(errno));
+ goto i2cr_cleanup;
+ }
+
+ /* if we need to send addr, use combined transaction */
+ if (addr_len > 0) {
+ /* build struct i2c_msg 0 */
+ message[0].addr = device_addr;
+ message[0].flags = 0;
+ message[0].len = addr_len;
+ temp = cell_addr;
+ /* store addr into buffer */
+ for (i = addr_len - 1; i >= 0; i--) {
+ addrbuf[i] = temp & 0xff;
+ temp >>= 8;
+ }
+ message[0].buf = addrbuf;
+
+ /* build struct i2c_msg 1 */
+ message[1].addr = device_addr;
+ message[1].flags = I2C_M_RD;
+ message[1].len = data_len;
+ message[1].buf = buf;
+
+ /* build arg */
+ rdwr_arg.msgs = message;
+ rdwr_arg.nmsgs = 2;
+
+ return_code = ioctl(file, I2C_RDWR, &rdwr_arg);
+
+ /* since we pass in rdwr_arg.nmsgs = 2, expect a return of 2 on success */
+ if (return_code == 2) {
+ return_code = 0;
+ }
+
+ goto i2cr_cleanup;
+ }
+
+ /* setup device address */
+ if ((return_code = ioctl(file, I2C_SLAVE, (void *)(uintptr_t)device_addr)) <
+ 0) {
+ printf("I2C Error: Could not set device address to %x: %s", device_addr,
+ strerror(errno));
+ goto i2cr_cleanup;
+ }
+
+ /* now read data out of the device */
+ read_data_len = read(file, buf, data_len);
+ if (read_data_len == data_len) {
+ return_code = 0;
+ }
+
+i2cr_cleanup:
+ flock(file, LOCK_UN);
+ close(file);
+
+ return return_code;
+}
+
+int i2cw(int controller, uint8_t device_addr, uint32_t cell_addr,
+ uint32_t addr_len, uint32_t data_len, uint8_t *buf) {
+ char filename[FILENAME_SIZE];
+ int file;
+ int i;
+ uint32_t temp;
+ uint8_t tempbuf[I2C_PAGE_SIZE + 4];
+ int return_code;
+ uint8_t *writebuf = buf;
+ unsigned int write_data_len;
+
+ /* check data len */
+ if (data_len > I2C_PAGE_SIZE) {
+ return -1;
+ }
+
+ /* open the corrrsponding I2C adapter */
+ snprintf(filename, sizeof(filename), I2C_DEV_FILE, controller);
+ if ((file = open(filename, O_RDWR)) < 0) {
+ printf("I2C Error open file %s: %s", filename, strerror(errno));
+ return -1;
+ }
+
+ if ((return_code = flock(file, LOCK_EX)) < 0) {
+ printf("I2C Error lock file %s: %s", filename, strerror(errno));
+ goto i2cw_cleanup;
+ }
+
+ /* setup device address */
+ if ((return_code =
+ ioctl(file, I2C_SLAVE_FORCE, (void *)(uintptr_t)device_addr)) < 0) {
+ printf("I2C Error: Could not set device address to %x: %s", device_addr,
+ strerror(errno));
+ goto i2cw_cleanup;
+ }
+
+ /* if we need to send addr */
+ if (addr_len > 0) {
+ temp = cell_addr;
+ /* store addr into buffer */
+ for (i = (int)(addr_len - 1); i >= 0; i--) {
+ tempbuf[i] = temp & 0xff;
+ temp >>= 8;
+ }
+ /* copy data over into tempbuf, right after the cell address */
+ for (i = 0; i < (int)(data_len); i++) {
+ tempbuf[addr_len + i] = buf[i];
+ }
+ writebuf = tempbuf;
+ }
+
+ /* now write addr + data out to the device */
+ write_data_len = write(file, writebuf, addr_len + data_len);
+
+ if (write_data_len == (addr_len + data_len)) {
+ return_code = 0;
+ }
+
+i2cw_cleanup:
+ flock(file, LOCK_UN);
+ close(file);
+
+ return return_code;
+}
diff --git a/diags/chameleon/i2c.h b/diags/chameleon/i2c.h
new file mode 100644
index 0000000..0c5f028
--- /dev/null
+++ b/diags/chameleon/i2c.h
@@ -0,0 +1,44 @@
+/*
+ * (C) Copyright 2014 Google, Inc.
+ * All rights reserved.
+ *
+ */
+
+#ifndef optimus_i2c_h
+#define optimus_i2c_h
+
+#include <inttypes.h>
+
+#define I2C_DEV_FILE "/dev/i2c-%d"
+#define I2C_PAGE_SIZE 16
+#define I2C_M_RD 0x01
+#define FILENAME_SIZE 64
+
+/*
+ * I2C Message - used for pure i2c transaction, also from /dev interface
+ */
+struct i2c_msg {
+ uint16_t addr; /* slave address */
+ uint16_t flags;
+ uint16_t len; /* msg length */
+ uint8_t *buf; /* pointer to msg data */
+};
+
+/* This is the structure as used in the I2C_RDWR ioctl call */
+struct i2c_rdwr_ioctl_data {
+ struct i2c_msg *msgs; /* pointers to i2c_msgs */
+ uint32_t nmsgs; /* number of i2c_msgs */
+};
+
+#define I2C_SLAVE 0x0703 /* Change slave address */
+#define I2C_SLAVE_FORCE 0x0706 /* Use this slave address, even if it
+ is already in use by a driver! */
+#define I2C_RDWR 0x0707 /* Combined R/W transfer (one stop only) */
+
+int i2cr(int controller, uint8_t device_addr, uint32_t cell_addr,
+ uint32_t addr_len, uint32_t data_len, uint8_t* buf);
+
+int i2cw(int controller, uint8_t device_addr, uint32_t cell_addr,
+ uint32_t addr_len, uint32_t data_len, uint8_t* buf);
+
+#endif // optimus_i2c_h
diff --git a/diags/chameleon/i2c_cmd.c b/diags/chameleon/i2c_cmd.c
new file mode 100644
index 0000000..a7bfe32
--- /dev/null
+++ b/diags/chameleon/i2c_cmd.c
@@ -0,0 +1,182 @@
+/*
+ * (C) Copyright 2014 Google, Inc.
+ * All rights reserved.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "i2c.h"
+
+#define I2C_READ_BUF_SIZE 1024
+#define DISPLAY_WIDTH 8
+
+int i2cread(int argc, char *argv[]);
+int i2cwrite(int argc, char *argv[]);
+int i2cprobe(int argc, char *argv[]);
+
+static void i2cread_usage(void) {
+ printf(
+ "i2cread bus# dev-address register-offset"
+ " address-len num-byte-to-read\n");
+ printf("Example:\n");
+ printf("i2cread 1 0x2c 0x40 1 1\n");
+ printf(
+ "Read from bus 1 device 0x2c, register 0x40,"
+ " address length is 1, read 1 byte\n");
+}
+
+int i2cread(int argc, char *argv[]) {
+ uint8_t device_addr;
+ uint32_t cell_addr;
+ uint32_t addr_len;
+ uint32_t data_len;
+ uint8_t *buf;
+ int j, k;
+ int return_code;
+ int controller;
+
+ if (argc < 6) {
+ i2cread_usage();
+ return -1;
+ }
+
+ controller = strtoul(argv[1], NULL, 0);
+ device_addr = (uint8_t)strtoul(argv[2], NULL, 0);
+ cell_addr = strtoul(argv[3], NULL, 0);
+ addr_len = strtoul(argv[4], NULL, 0);
+ data_len = strtoul(argv[5], NULL, 0);
+
+ if (data_len >= I2C_READ_BUF_SIZE) {
+ printf("ERROR: Size %s too large\n", argv[5]);
+ return -1;
+ }
+
+ buf = (uint8_t *)malloc(I2C_READ_BUF_SIZE);
+ if (buf == NULL) {
+ printf("ERROR: malloc failed (out of memory)\n");
+ return -1;
+ }
+
+ return_code =
+ i2cr(controller, device_addr, cell_addr, addr_len, data_len, buf);
+ if (return_code != 0) {
+ printf("Read ERROR: return code = %d\n", return_code);
+ free(buf);
+ return return_code;
+ }
+
+ /* display */
+ for (j = 0; j < (int)(data_len); j += DISPLAY_WIDTH) {
+ printf("\n@0x%04X\t:", cell_addr + j);
+ for (k = j; (k < (int)(data_len)) && (k < (j + DISPLAY_WIDTH)); k++) {
+ printf("%02X", buf[k]);
+ }
+ /* fill up space if finish before display width */
+ if ((k == (int)(data_len)) && (k < (j + DISPLAY_WIDTH))) {
+ for (k = data_len; k < (j + DISPLAY_WIDTH); k++) {
+ printf(" ");
+ }
+ }
+ printf("\t");
+ for (k = j; (k < (int)(data_len)) && (k < (j + DISPLAY_WIDTH)); k++) {
+ if ((buf[k] >= 0x20) && (buf[k] < 0x7f)) {
+ printf("%c", buf[k]);
+ } else {
+ printf("%c", '.');
+ }
+ }
+ printf("\n");
+ }
+
+ printf("\n--------------------------------------------\n");
+
+ free(buf);
+ return 0;
+}
+
+static void i2cwrite_usage(void) {
+ printf(
+ "i2cwrite bus# dev-address register-offset"
+ " address-len data-len data\n");
+ printf("Example:\n");
+ printf("i2cwrite 1 0x2c 0x40 1 1 0x80\n");
+ printf(
+ "Write to bus 1 device 0x2c, register 0x40,"
+ " address length is 1, 1 byte data, data value is 0x80\n");
+}
+
+int i2cwrite(int argc, char *argv[]) {
+ uint8_t device_addr;
+ uint32_t cell_addr;
+ uint32_t addr_len;
+ uint32_t data_len;
+ uint32_t data;
+ uint8_t buf[4];
+ int return_code;
+ int controller;
+ int i;
+
+ if (argc < 6) {
+ i2cwrite_usage();
+ return -1;
+ }
+
+ controller = strtoul(argv[1], NULL, 0);
+ device_addr = (uint8_t)strtoul(argv[2], NULL, 0);
+ cell_addr = strtoul(argv[3], NULL, 0);
+ addr_len = strtoul(argv[4], NULL, 0);
+ data_len = strtoul(argv[5], NULL, 0);
+
+ if (data_len > 4) {
+ printf("ERROR: Size %s too large\n", argv[5]);
+ return -1;
+ }
+
+ data = strtoul(argv[6], NULL, 0);
+
+ /* store data into buffer */
+ for (i = data_len - 1; i >= 0; i--) {
+ buf[i] = data & 0xff;
+ data >>= 8;
+ }
+
+ return_code =
+ i2cw(controller, device_addr, cell_addr, addr_len, data_len, buf);
+ if (return_code != 0) {
+ printf("Write ERROR: return code = %d\n", return_code);
+ return return_code;
+ }
+
+ return 0;
+}
+
+static void i2cprobe_usage(void) {
+ printf("i2cprobe bus#\n");
+ printf("Example:\n");
+ printf("i2cprobe 2\n");
+}
+
+int i2cprobe(int argc, char *argv[]) {
+ uint8_t device_addr;
+ uint8_t buf[1];
+ int return_code;
+ int controller;
+
+ if (argc < 2) {
+ i2cprobe_usage();
+ return -1;
+ }
+
+ controller = strtoul(argv[1], NULL, 0);
+
+ for (device_addr = 1; device_addr < 127; device_addr++) {
+ return_code = i2cr(controller, device_addr, 0, 1, 1, buf);
+ if (return_code == 0) {
+ printf("Address 0x%02X responding\n", device_addr);
+ }
+ }
+
+ return 0;
+}
diff --git a/diags/chameleon/mdio.c b/diags/chameleon/mdio.c
new file mode 100644
index 0000000..0df12ca
--- /dev/null
+++ b/diags/chameleon/mdio.c
@@ -0,0 +1,66 @@
+#include <errno.h>
+#include <net/if.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include <linux/sockios.h>
+#include <linux/types.h>
+
+static int skfd = -1;
+static struct ifreq ifr;
+
+struct mii_data {
+ __u16 phy_id;
+ __u16 reg_num;
+ __u16 val_in;
+ __u16 val_out;
+};
+
+int mdio_read(int location) {
+ struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
+ mii->reg_num = location;
+ if (ioctl(skfd, SIOCGMIIREG, &ifr) < 0) {
+ fprintf(stderr, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name,
+ strerror(errno));
+ return -1;
+ }
+ return mii->val_out;
+}
+
+int mdio_write(int location, int value) {
+ struct mii_data *mii = (struct mii_data *)&ifr.ifr_data;
+ mii->reg_num = location;
+ mii->val_in = value;
+ if (ioctl(skfd, SIOCSMIIREG, &ifr) < 0) {
+ fprintf(stderr, "SIOCSMIIREG on %s failed: %s\n", ifr.ifr_name,
+ strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+void mdio_init() {
+ if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("socket init failed");
+ exit(-1);
+ }
+}
+
+int mdio_set_interface(const char *ifname) {
+ strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ if (ioctl(skfd, SIOCGMIIPHY, &ifr) < 0) {
+ if (errno != ENODEV)
+ fprintf(stderr, "SIOCGMIIPHY on '%s' failed: %s\n", ifname,
+ strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+void mdio_done() { close(skfd); }
diff --git a/diags/chameleon/mdio.h b/diags/chameleon/mdio.h
new file mode 100644
index 0000000..16159c5
--- /dev/null
+++ b/diags/chameleon/mdio.h
@@ -0,0 +1,17 @@
+#ifndef VENDOR_GOOGLE_DIAGS_SPACECAST_MDIO_H_
+#define VENDOR_GOOGLE_DIAGS_SPACECAST_MDIO_H_
+
+// In order to read/write PHY registers, it needs to do it in the
+// following sequence:
+// mdio_init
+// mdio_set_interface
+// mdio_read and/or mdio_write (as many as required)
+// mdio_done
+
+int mdio_read(int location);
+int mdio_write(int location, int value);
+void mdio_init();
+int mdio_set_interface(const char* ifname);
+void mdio_done();
+
+#endif // VENDOR_GOOGLE_DIAGS_SPACECAST_MDIO_H_
diff --git a/diags/chameleon/sfp.c b/diags/chameleon/sfp.c
new file mode 100644
index 0000000..e17e02d
--- /dev/null
+++ b/diags/chameleon/sfp.c
@@ -0,0 +1,350 @@
+/*
+ * (C) Copyright 2015 Google, Inc.
+ * All rights reserved.
+ *
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "../common/io.h"
+#include "../common/util.h"
+#include "i2c.h"
+
+#define SFP_BUS 0
+#define SFP_A0_ADDR 0x50
+#define SFP_A2_ADDR 0x51
+#define SFP_ADDR_LEN 1
+#define SFP_REG_LEN 1
+#define SFP_MAX_DATA_LEN 128
+#define SFP_INFO_REG_ADDR 0x60
+#define SFP_INFO_REG_LEN 16
+#define SFP_VENDOR_REG_ADDR 20
+#define SFP_VENDOR_REG_LEN 16
+#define SFP_PN_REG_ADDR 40
+#define SFP_PN_REG_LEN 16
+#define SFP_SN_REG_ADDR 68
+#define SFP_SN_REG_LEN 16
+#define SFP_DATE_REG_ADDR 84
+#define SFP_DATE_REG_LEN 8
+#define SFP_WL_REG_ADDR 144
+#define SFP_WL_REG_LEN 2
+#define SFP_PW_REG 0x7B
+#define SFP_PW_REG_LEN 4
+
+static void sfp_reg_read_usage(void) {
+ printf("sfp_reg_read <addr>\n");
+ printf("read SFP registers\n");
+ printf("Example:\n");
+ printf("sfp_reg_read 0x40\n");
+}
+
+int sfp_reg_read(int argc, char *argv[]) {
+ unsigned int reg_addr;
+ uint8_t value;
+
+ if (argc != 2) {
+ sfp_reg_read_usage();
+ return -1;
+ }
+
+ reg_addr = get_num(argv[1]);
+ if (i2cr(SFP_BUS, SFP_A0_ADDR, reg_addr, SFP_ADDR_LEN, SFP_REG_LEN, &value) !=
+ 0) {
+ printf("SFP read address 0x%x failed\n", reg_addr);
+ return -1;
+ }
+ printf("SFP 0x%x = 0x%x\n", reg_addr, value);
+
+ return 0;
+}
+
+static void sfp_reg_write_usage(void) {
+ printf("sfp_reg_write <addr> <data>\n");
+ printf("write SFP registers\n");
+ printf("Example:\n");
+ printf("sfp_reg_write 0x60 0x0\n");
+}
+
+int sfp_reg_write(int argc, char *argv[]) {
+ unsigned int reg_addr;
+ uint8_t value;
+
+ if (argc != 3) {
+ sfp_reg_write_usage();
+ return -1;
+ }
+
+ reg_addr = get_num(argv[1]);
+ value = get_num(argv[2]);
+ if (i2cw(SFP_BUS, SFP_A0_ADDR, reg_addr, SFP_ADDR_LEN, SFP_REG_LEN, &value) !=
+ 0) {
+ printf("SFP write address 0x%x value 0x%x failed\n", reg_addr, value);
+ return -1;
+ }
+ printf("SFP 0x%x set to 0x%x\n", reg_addr, value);
+
+ return 0;
+}
+
+static void sfp_diags_reg_read_usage(void) {
+ printf("sfp_diags_reg_read <addr>\n");
+ printf("read SFP 0xA2 registers\n");
+ printf("Example:\n");
+ printf("sfp_diags_reg_read 0x40\n");
+}
+
+int sfp_diags_reg_read(int argc, char *argv[]) {
+ unsigned int reg_addr;
+ uint8_t value;
+
+ if (argc != 2) {
+ sfp_diags_reg_read_usage();
+ return -1;
+ }
+
+ reg_addr = get_num(argv[1]);
+ if (i2cr(SFP_BUS, SFP_A2_ADDR, reg_addr, SFP_ADDR_LEN, SFP_REG_LEN, &value) !=
+ 0) {
+ printf("SFP 0xA2 read address 0x%x failed\n", reg_addr);
+ return -1;
+ }
+ printf("SFP 0xA2 0x%x = 0x%x\n", reg_addr, value);
+
+ return 0;
+}
+
+static void sfp_diags_reg_write_usage(void) {
+ printf("sfp_diags_reg_write <addr> <data>\n");
+ printf("write SFP 0xA2 registers\n");
+ printf("Example:\n");
+ printf("sfp_diags_reg_write 0x60 0x0\n");
+}
+
+int sfp_diags_reg_write(int argc, char *argv[]) {
+ unsigned int reg_addr;
+ uint8_t value;
+
+ if (argc != 3) {
+ sfp_diags_reg_write_usage();
+ return -1;
+ }
+
+ reg_addr = get_num(argv[1]);
+ value = get_num(argv[2]);
+ if (i2cw(SFP_BUS, SFP_A2_ADDR, reg_addr, SFP_ADDR_LEN, SFP_REG_LEN, &value) !=
+ 0) {
+ printf("SFP write 0xA2 address 0x%x value 0x%x failed\n", reg_addr, value);
+ return -1;
+ }
+ printf("SFP 0xA2 0x%x set to 0x%x\n", reg_addr, value);
+
+ return 0;
+}
+
+static void sfp_info_usage(void) {
+ printf("sfp_info\n");
+ printf("read SFP info\n");
+ printf("Example:\n");
+ printf("sfp_info\n");
+}
+
+int sfp_info(int argc, char *argv[]) {
+ uint8_t value[SFP_INFO_REG_LEN];
+ float temp;
+ float vcc, tx_bias, tx_power, rx_power, mod_curr;
+
+ if (argc != 1 || argv == NULL) {
+ sfp_info_usage();
+ return -1;
+ }
+
+ if (i2cr(SFP_BUS, SFP_A2_ADDR, SFP_INFO_REG_ADDR, SFP_ADDR_LEN,
+ SFP_INFO_REG_LEN, value) != 0) {
+ printf("SFP read address %d failed\n", SFP_INFO_REG_ADDR);
+ return -1;
+ }
+ if (value[0] & 0x80) {
+ value[0] &= 0x7F;
+ temp = -128.0 + value[0] + ((float)value[1]) / 256.0;
+ } else {
+ temp = value[0] + ((float)value[1]) / 256.0;
+ }
+ vcc = ((float)((value[2] << 8) + value[3])) / 10000.0;
+ tx_bias = ((float)((value[4] << 8) + value[5])) / 1000.0;
+ tx_power = ((float)((value[6] << 8) + value[7])) / 10000.0;
+ rx_power = ((float)((value[8] << 8) + value[9])) / 10000.0;
+ mod_curr = ((float)((value[12] << 8) + value[13])) / 1000.0;
+ printf("SFP temp: %f, Vcc: %3.3f V, TX bias %3.3f mA\n", temp, vcc, tx_bias);
+ printf(" TX power: %3.3f mW, RX power: %3.3f mW, mod curr: %3.3f mA\n",
+ tx_power, rx_power, mod_curr);
+
+ return 0;
+}
+
+static void sfp_vendor_usage(void) {
+ printf("sfp_vendor\n");
+ printf("read SFP vendor\n");
+ printf("Example:\n");
+ printf("sfp_vendor\n");
+}
+
+int sfp_vendor(int argc, char *argv[]) {
+ uint8_t value[SFP_MAX_DATA_LEN];
+
+ if (argc != 1 || argv == NULL) {
+ sfp_vendor_usage();
+ return -1;
+ }
+
+ printf("SFP vendor:\n");
+ if (i2cr(SFP_BUS, SFP_A0_ADDR, SFP_VENDOR_REG_ADDR, SFP_ADDR_LEN,
+ SFP_VENDOR_REG_LEN, value) != 0) {
+ printf("SFP read address %d failed\n", SFP_VENDOR_REG_ADDR);
+ return -1;
+ }
+ value[SFP_VENDOR_REG_LEN] = '\0';
+ printf(" Name: %s\n", value);
+ if (i2cr(SFP_BUS, SFP_A0_ADDR, SFP_PN_REG_ADDR, SFP_ADDR_LEN, SFP_PN_REG_LEN,
+ value) != 0) {
+ printf("SFP read address %d failed\n", SFP_PN_REG_ADDR);
+ return -1;
+ }
+ value[SFP_PN_REG_LEN] = '\0';
+ printf(" PN: %s\n", value);
+ if (i2cr(SFP_BUS, SFP_A0_ADDR, SFP_SN_REG_ADDR, SFP_ADDR_LEN, SFP_SN_REG_LEN,
+ value) != 0) {
+ printf("SFP read address %d failed\n", SFP_SN_REG_ADDR);
+ return -1;
+ }
+ value[SFP_SN_REG_LEN] = '\0';
+ printf(" SN: %s\n", value);
+ if (i2cr(SFP_BUS, SFP_A0_ADDR, SFP_DATE_REG_ADDR, SFP_ADDR_LEN,
+ SFP_DATE_REG_LEN, value) != 0) {
+ printf("SFP read address %d failed\n", SFP_DATE_REG_ADDR);
+ return -1;
+ }
+ value[SFP_DATE_REG_LEN] = '\0';
+ printf(" Date: %s\n", value);
+
+ return 0;
+}
+
+static void sfp_pn_usage(void) {
+ printf("sfp_pn\n");
+ printf("read SFP part number\n");
+ printf("Example:\n");
+ printf("sfp_pn\n");
+}
+
+int sfp_pn(int argc, char *argv[]) {
+ uint8_t value[SFP_MAX_DATA_LEN];
+
+ if (argc != 1 || argv == NULL) {
+ sfp_pn_usage();
+ return -1;
+ }
+
+ if (i2cr(SFP_BUS, SFP_A0_ADDR, SFP_PN_REG_ADDR, SFP_ADDR_LEN, SFP_PN_REG_LEN,
+ value) != 0) {
+ printf("SFP read address %d failed\n", SFP_PN_REG_ADDR);
+ return -1;
+ }
+ value[SFP_PN_REG_LEN] = '\0';
+ printf("SFP part number: %s\n", value);
+
+ return 0;
+}
+
+static void sfp_wavelength_usage(void) {
+ printf("sfp_wavelength\n");
+ printf("read SFP laser wavelength\n");
+ printf("Example:\n");
+ printf("sfp_wavelength\n");
+}
+
+int sfp_wavelength(int argc, char *argv[]) {
+ uint8_t value[SFP_MAX_DATA_LEN];
+ unsigned int data;
+
+ if (argc != 1 || argv == NULL) {
+ sfp_wavelength_usage();
+ return -1;
+ }
+
+ if (i2cr(SFP_BUS, SFP_A2_ADDR, SFP_WL_REG_ADDR, SFP_ADDR_LEN, SFP_WL_REG_LEN,
+ value) != 0) {
+ printf("SFP read address %d failed\n", SFP_WL_REG_ADDR);
+ return -1;
+ }
+ data = (value[0] << 8) + value[1];
+ printf("SFP wavelength: %d\n", data);
+
+ return 0;
+}
+
+static void sfp_set_wavelength_usage(void) {
+ printf("sfp_set_wavelength <wavelength>\n");
+ printf("set SFP laser wavelength\n");
+ printf("Example:\n");
+ printf("sfp_set_wavelength 1520\n");
+}
+
+int sfp_set_wavelength(int argc, char *argv[]) {
+ uint8_t value[SFP_MAX_DATA_LEN];
+ unsigned int data;
+
+ if (argc != 2) {
+ sfp_set_wavelength_usage();
+ return -1;
+ }
+
+ data = get_num(argv[1]);
+ value[0] = (data >> 8);
+ value[1] = data & 0xFF;
+ if (i2cw(SFP_BUS, SFP_A2_ADDR, SFP_WL_REG_ADDR, SFP_ADDR_LEN, SFP_WL_REG_LEN,
+ value) != 0) {
+ printf("SFP write address %d of %d failed\n", SFP_WL_REG_ADDR, data);
+ return -1;
+ }
+ data = (value[0] << 8) + value[1];
+ printf("SFP wavelength: %d\n", data);
+
+ return 0;
+}
+
+static void sfp_set_pw_usage(void) {
+ printf("sfp_set_pw <password>\n");
+ printf("set SFP access password\n");
+ printf("Example:\n");
+ printf("sfp_set_pw 0x80818283\n");
+}
+
+int sfp_set_pw(int argc, char *argv[]) {
+ uint8_t value[SFP_MAX_DATA_LEN];
+ unsigned int data;
+
+ if (argc != 2) {
+ sfp_set_pw_usage();
+ return -1;
+ }
+
+ data = get_num(argv[1]);
+ value[0] = (data >> 24) & 0xFF;
+ value[1] = (data >> 16) & 0xFF;
+ value[2] = (data >> 8) & 0xFF;
+ value[3] = data & 0xFF;
+ if (i2cw(SFP_BUS, SFP_A2_ADDR, SFP_PW_REG, SFP_ADDR_LEN, SFP_PW_REG_LEN,
+ value) != 0) {
+ printf("SFP write address %d of %d failed\n", SFP_PW_REG, data);
+ return -1;
+ }
+ printf("SFP password set to 0x%2x%2x%2x%2x\n", value[0], value[1], value[2],
+ value[3]);
+
+ return 0;
+}
diff --git a/diags/common/util.c b/diags/common/util.c
index 41802b1..fae99ab 100644
--- a/diags/common/util.c
+++ b/diags/common/util.c
@@ -77,3 +77,16 @@
printf("ERROR: system command %s return %d\n", cmd, rc);
}
}
+
+unsigned int get_num(char *numstr) {
+ unsigned int value;
+
+ if (strlen(numstr) > 2) {
+ if (strncmp(numstr, "0x", 2) == 0) {
+ value = strtoul(numstr, NULL, 16);
+ return value;
+ }
+ }
+ value = strtoul(numstr, NULL, 10);
+ return value;
+}
diff --git a/diags/common/util.h b/diags/common/util.h
index 340b582..f6717b7 100644
--- a/diags/common/util.h
+++ b/diags/common/util.h
@@ -23,4 +23,6 @@
void system_cmd(const char *cmd);
+unsigned int get_num(char *numstr);
+
#endif // VENDOR_GOOGLE_DIAGS_WINDCHARGER_UTIL_H_
diff --git a/ginstall/ginstall.py b/ginstall/ginstall.py
index 5db5493..f061157 100755
--- a/ginstall/ginstall.py
+++ b/ginstall/ginstall.py
@@ -36,16 +36,18 @@
optspec = """
ginstall -p <partition>
-ginstall -p <partition> -t <tarfile> [options...]
+ginstall [-t <tarfile>] [--drm <blob>] [options...]
--
-t,tar= *.gi file to install, from a local path or uri://path
+t,tar= path to a *.gi file to install; may be - for STDIN, a file on the\
+ filesystem, or an http[s]:// URI
skiploader skip installing bootloader (dev-only)
manifest= manifest file
drm= drm blob filename to install
-p,partition= partition to install to (primary, secondary, or other)
+p,partition= partition to boot to on next boot (other, primary, or secondary)\
+ and to unpack .gi image to (if -t is given)
q,quiet suppress unnecessary output
skiploadersig suppress checking the loader signature
-b,basepath= for tests, prepend a path to all files accessed.
+b,basepath= for tests, prepend a path to all files accessed
"""
# Error codes.
@@ -625,6 +627,14 @@
'gftv200-39-pre1 and before.')
+def CheckMultiLoader(manifest):
+ """Check if this ginstall image supports platform-named loaders."""
+ multiloader = manifest.get('multiloader')
+ if not multiloader:
+ return False
+ return True
+
+
class ProgressBar(object):
"""Progress bar that prints one dot per 1MB."""
@@ -863,6 +873,12 @@
CheckMinimumVersion(manifest)
CheckMisc(manifest)
+ loader_bin_list = ['loader.img', 'loader.bin']
+ loader_sig_list = ['loader.sig']
+ if CheckMultiLoader(manifest):
+ loader_bin_list = ['loader.%s.bin' % GetPlatform().lower()]
+ loader_sig_list = ['loader.%s.sig' % GetPlatform().lower()]
+
uloader = loader = None
uloadersig = FileWithSecureHash(StringIO.StringIO(''), 'badsig')
loadersig = FileWithSecureHash(StringIO.StringIO(''), 'badsig')
@@ -878,10 +894,10 @@
elif ti.name.startswith('rootfs.'):
fh = FileWithSecureHash(tar.extractfile(ti), secure_hash)
InstallRootfs(fh, partition)
- elif ti.name in ['loader.img', 'loader.bin']:
+ elif ti.name in loader_bin_list:
buf = StringIO.StringIO(tar.extractfile(ti).read())
loader = FileWithSecureHash(buf, secure_hash)
- elif ti.name == 'loader.sig':
+ elif ti.name in loader_sig_list:
buf = StringIO.StringIO(tar.extractfile(ti).read())
loadersig = FileWithSecureHash(buf, secure_hash)
elif ti.name == 'uloader.img':
@@ -927,7 +943,10 @@
pass
try:
- return open(path)
+ if path == '-':
+ return sys.stdin
+ else:
+ return open(path)
except ValueError:
pass
diff --git a/ginstall/ginstall_test.py b/ginstall/ginstall_test.py
index 8deac64..a4e3c8a 100755
--- a/ginstall/ginstall_test.py
+++ b/ginstall/ginstall_test.py
@@ -21,6 +21,7 @@
import shutil
import StringIO
import struct
+import sys
import tempfile
import unittest
import ginstall
@@ -365,6 +366,21 @@
total = ginstall.GetMemTotal()
self.assertTrue(total < 4*1e9)
+ def testOpenPathOrUrl(self):
+ # URL
+ two_oh_four = ginstall.OpenPathOrUrl('http://www.gstatic.com/generate_204')
+ self.assertEqual(204, two_oh_four.getcode())
+
+ # on-disk file
+ on_disk_file = tempfile.NamedTemporaryFile()
+ testdata = os.urandom(16)
+ on_disk_file.write(testdata)
+ on_disk_file.flush()
+ self.assertEqual(ginstall.OpenPathOrUrl(on_disk_file.name).read(), testdata)
+
+ # stdin (-)
+ self.assertEqual(ginstall.OpenPathOrUrl('-'), sys.stdin)
+
if __name__ == '__main__':
unittest.main()
diff --git a/ginstall/install_test.sh b/ginstall/install_test.sh
index 4338bac..ec372c5 100755
--- a/ginstall/install_test.sh
+++ b/ginstall/install_test.sh
@@ -5,6 +5,7 @@
tmpdir="$(mktemp -d)"
export PATH="$tmpdir/bin:${PATH}"
export GINSTALL_OUT_FILE="$tmpdir/out"
+psiz=$(stat --format=%s testdata/img/loader.gflt110.bin)
lsiz=$(stat --format=%s testdata/img/loader.img)
ksiz=$(stat --format=%s testdata/img/kernel.img)
rsiz=$(stat --format=%s testdata/img/rootfs.img)
@@ -195,6 +196,45 @@
+# GFLT110 with gflt110.bin loader.
+echo; echo; echo GFLT110 with platform loader
+setup_fakeroot GFLT110
+expected="\
+psback
+logos ginstall
+flash_unlock ${tmpdir}/dev/mtd6
+flash_erase --quiet ${tmpdir}/dev/mtd6 0 0
+flash_unlock ${tmpdir}/dev/mtd0
+flash_erase --quiet ${tmpdir}/dev/mtd0 0 0
+hnvram -q -w ACTIVATED_KERNEL_NAME=kernel0"
+
+WVPASS ./ginstall.py --basepath="$tmpdir" --tar=./testdata/img/image_gflt110_platform_loader.gi --partition=primary --skiploadersig
+WVPASSEQ "$expected" "$(cat $GINSTALL_OUT_FILE)"
+WVPASS cmp --bytes="$psiz" "${tmpdir}/dev/mtd0" testdata/img/loader.gflt110.bin
+WVPASS cmp --bytes="$ksiz" "${tmpdir}/dev/mtd6" testdata/img/kernel.img
+
+
+
+# GFLT110 with both loaders with the MANIFEST containing "multiloader: 1"
+echo; echo; echo GFLT110 with both loaders
+setup_fakeroot GFLT110
+expected="\
+psback
+logos ginstall
+flash_unlock ${tmpdir}/dev/mtd6
+flash_erase --quiet ${tmpdir}/dev/mtd6 0 0
+flash_unlock ${tmpdir}/dev/mtd0
+flash_erase --quiet ${tmpdir}/dev/mtd0 0 0
+hnvram -q -w ACTIVATED_KERNEL_NAME=kernel0"
+
+WVPASS ./ginstall.py --basepath="$tmpdir" --tar=./testdata/img/image_gflt110_both_loaders.gi --partition=primary --skiploadersig
+WVPASSEQ "$expected" "$(cat $GINSTALL_OUT_FILE)"
+WVFAIL cmp --bytes="$lsiz" "${tmpdir}/dev/mtd0" testdata/img/loader.bin
+WVPASS cmp --bytes="$psiz" "${tmpdir}/dev/mtd0" testdata/img/loader.gflt110.bin
+WVPASS cmp --bytes="$ksiz" "${tmpdir}/dev/mtd6" testdata/img/kernel.img
+
+
+
echo; echo; echo MANIFEST with Bad checksums
setup_fakeroot GFHD100
echo "This should not be touched" >"${tmpdir}/dev/mtd0"
diff --git a/ginstall/testdata/img/image_gflt110_both_loaders.gi b/ginstall/testdata/img/image_gflt110_both_loaders.gi
new file mode 100644
index 0000000..62f2a03
--- /dev/null
+++ b/ginstall/testdata/img/image_gflt110_both_loaders.gi
Binary files differ
diff --git a/ginstall/testdata/img/image_gflt110_platform_loader.gi b/ginstall/testdata/img/image_gflt110_platform_loader.gi
new file mode 100644
index 0000000..8d7ed9b
--- /dev/null
+++ b/ginstall/testdata/img/image_gflt110_platform_loader.gi
Binary files differ
diff --git a/ginstall/testdata/img/loader.gflt110.bin b/ginstall/testdata/img/loader.gflt110.bin
new file mode 100644
index 0000000..a95b6ae
--- /dev/null
+++ b/ginstall/testdata/img/loader.gflt110.bin
@@ -0,0 +1 @@
+gflt110.bin
\ No newline at end of file
diff --git a/hnvram/hnvram_main.c b/hnvram/hnvram_main.c
index b850048..eb0f306 100644
--- a/hnvram/hnvram_main.c
+++ b/hnvram/hnvram_main.c
@@ -1,7 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
// Author: dgentry@google.com (Denny Gentry)
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
+
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -16,23 +19,28 @@
// Number of bytes of GPN to be represented as hex data
#define GPN_HEX_BYTES 4
+// Holds whether -w can create new variables in NVRAM. Set with -n
+int can_add_flag = 0;
+
/* To avoid modifying the HMX code, we supply dummy versions of two
* missing routines to satisfy the linker. These are used when writing
* the complete NVRAM partiton, which we do not need in this utility. */
DRV_Error DRV_NANDFLASH_GetNvramHandle(int handle) {
return DRV_ERR;
}
-DRV_Error DRV_FLASH_Write(int offset, char *data, int nDataSize) {
+DRV_Error DRV_FLASH_Write(int offset, char* data, int nDataSize) {
return DRV_ERR;
}
void usage(const char* progname) {
- printf("Usage: %s [-d | [-q|-b] -r VARNAME] [-w VARNAME=value]\n", progname);
+ printf("Usage: %s [-d | [-q|-b] [-r|-k] VARNAME] [ [-n] -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-k VARNAME : delete existing key/value pair from NVRAM.\n");
}
// Format of data in the NVRAM
@@ -83,6 +91,7 @@
{"LASER_CHANNEL", NVRAM_FIELD_LASER_CHANNEL, HNVRAM_STRING},
{"MAC_ADDR_PON", NVRAM_FIELD_MAC_ADDR_PON, HNVRAM_MAC},
{"PRODUCTION_UNIT", NVRAM_FIELD_PRODUCTION_UNIT, HNVRAM_STRING},
+ {"BOOT_TARGET", NVRAM_FIELD_BOOT_TARGET, HNVRAM_STRING},
};
const hnvram_field_t* get_nvram_field(const char* name) {
@@ -103,28 +112,25 @@
// ------------------ READ NVRAM -----------------------------
-void format_string(const char* data, char* output, int outlen) {
+void format_string(const unsigned char* data, char* output, int outlen) {
snprintf(output, outlen, "%s", data);
}
-void format_mac(const char* data, char* output, int outlen) {
- const unsigned char* mac = (const unsigned char*) data;
+void format_mac(const unsigned char* data, char* output, int outlen) {
snprintf(output, outlen, "%02hx:%02hx:%02hx:%02hx:%02hx:%02hx",
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ data[0], data[1], data[2], data[3], data[4], data[5]);
}
-void format_hmxswvers(const char* data, char* output, int outlen) {
- const unsigned char* udata = (const unsigned char*) data;
- snprintf(output, outlen, "%hhu.%hhu", udata[1], udata[0]);
+void format_hmxswvers(const unsigned char* data, char* output, int outlen) {
+ snprintf(output, outlen, "%hhu.%hhu", data[1], data[0]);
}
-void format_uint8(const char* data, char* output, int outlen) {
- const unsigned char* d = (const unsigned char*)data;
- snprintf(output, outlen, "%u", d[0]);
+void format_uint8(const unsigned char* data, char* output, int outlen) {
+ snprintf(output, outlen, "%u", data[0]);
}
-void format_hexstring(const char* data, int datalen, char* output, int outlen) {
- const unsigned char* d = (const unsigned char*)data;
+void format_hexstring(const unsigned char* data, int datalen, char* output,
+ int outlen) {
int i;
if (outlen < (datalen * 2 + 1)) {
fprintf(stderr, "%s buffer too small %d < %d",
@@ -132,11 +138,11 @@
exit(1);
}
for (i = 0; i < datalen; ++i) {
- snprintf(output + (i * 2), 3, "%02x", d[i]);
+ snprintf(output + (i * 2), 3, "%02x", data[i]);
}
}
-void format_gpn(const char* data, const int data_len, char* output,
+void format_gpn(const unsigned char* data, const int data_len, char* output,
int outlen) {
// Format first 4 bytes as 8 digit hex.
if (data_len == GPN_HEX_BYTES)
@@ -145,7 +151,7 @@
format_string(data, output, outlen);
}
-char* format_nvram(hnvram_format_e format, const char* data,
+char* format_nvram(hnvram_format_e format, const unsigned char* data,
const int data_len, char* output, int outlen) {
output[0] = '\0';
switch(format) {
@@ -162,7 +168,7 @@
int read_raw_nvram(const char* name, char* output, int outlen) {
const hnvram_field_t* field = get_nvram_field(name);
- int ret;
+ unsigned int ret;
if (field == NULL) {
return -1;
}
@@ -179,23 +185,33 @@
return -1;
}
- return ret;
+ return (int)ret;
}
char* read_nvram(const char* name, char* output, int outlen, int quiet) {
const hnvram_field_t* field = get_nvram_field(name);
- if (field == NULL) {
- return NULL;
- }
+ int is_field = (field != NULL);
- char data[NVRAM_MAX_DATA] = {0};
- int data_len = 0;
- if (HMX_NVRAM_GetField(field->nvram_type, 0, data, sizeof(data)) != DRV_OK ||
- HMX_NVRAM_GetLength(field->nvram_type, &data_len) != DRV_OK) {
- return NULL;
+ unsigned char data[NVRAM_MAX_DATA] = {0};
+ unsigned int data_len = 0;
+ hnvram_format_e format_type;
+ if (is_field) {
+ format_type = field->format;
+ if (HMX_NVRAM_GetField(field->nvram_type, 0, data, sizeof(data)) != DRV_OK ||
+ HMX_NVRAM_GetLength(field->nvram_type, &data_len) != DRV_OK) {
+ return NULL;
+ }
+ } else {
+ format_type = HNVRAM_STRING;
+ DRV_Error e = HMX_NVRAM_Read(HMX_NVRAM_PARTITION_RW, (unsigned char*)name,
+ 0, data, sizeof(data), &data_len);
+ if (e != DRV_OK) {
+ return NULL;
+ }
}
char formatbuf[NVRAM_MAX_DATA * 2];
- char* nv = format_nvram(field->format, data, data_len, formatbuf, sizeof(formatbuf));
+ char* nv = format_nvram(format_type, data, data_len, formatbuf,
+ sizeof(formatbuf));
if (quiet) {
snprintf(output, outlen, "%s", nv);
} else {
@@ -203,13 +219,11 @@
}
return output;
}
-
-
// ----------------- WRITE NVRAM -----------------------------
unsigned char* parse_string(const char* input,
- unsigned char* output, int* outlen) {
+ unsigned char* output, unsigned int* outlen) {
int len = strlen(input);
if (len > *outlen) {
len = *outlen;
@@ -221,7 +235,7 @@
}
unsigned char* parse_mac(const char* input,
- unsigned char* output, int* outlen) {
+ unsigned char* output, unsigned int* outlen) {
if (*outlen < 6) return NULL;
if (sscanf(input, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
@@ -234,7 +248,7 @@
}
unsigned char* parse_hmxswvers(const char* input,
- unsigned char* output, int* outlen) {
+ unsigned char* output, unsigned int* outlen) {
if (*outlen < 2) return NULL;
if (sscanf(input, "%hhd.%hhd", &output[1], &output[0]) != 2) {
@@ -245,7 +259,7 @@
}
unsigned char* parse_uint8(const char* input,
- unsigned char* output, int* outlen) {
+ unsigned char* output, unsigned int* outlen) {
if (*outlen < 1) return NULL;
output[0] = input[0] - '0';
@@ -263,8 +277,8 @@
}
unsigned char* parse_hexstring(const char* input,
- unsigned char* output, int* outlen) {
- int i, len = strlen(input) / 2;
+ unsigned char* output, unsigned int* outlen) {
+ unsigned int i, len = strlen(input) / 2;
if (*outlen < len) {
len = *outlen;
}
@@ -293,7 +307,7 @@
}
unsigned char* parse_gpn(const char* input,
- unsigned char* output, int* outlen) {
+ unsigned char* output, unsigned int* outlen) {
if (*outlen < 4) return NULL;
// Old GPN format: 8-digit hex string
@@ -311,7 +325,7 @@
}
unsigned char* parse_nvram(hnvram_format_e format, const char* input,
- unsigned char* output, int* outlen) {
+ unsigned char* output, unsigned int* outlen) {
output[0] = '\0';
switch(format) {
case HNVRAM_STRING:
@@ -336,6 +350,15 @@
return NULL;
}
+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
+ return DRV_OK;
+ }
+ return e;
+}
int write_nvram(char* optarg) {
char* equal = strchr(optarg, '=');
@@ -348,25 +371,45 @@
char* value = ++equal;
const hnvram_field_t* field = get_nvram_field(name);
- if (field == NULL) {
- return -2;
+ int is_field = (field != NULL);
+
+ hnvram_format_e format_type;
+ if (is_field) {
+ format_type = field->format;
+ } else {
+ format_type = HNVRAM_STRING;
}
unsigned char nvram_value[NVRAM_MAX_DATA];
- int nvram_len = sizeof(nvram_value);
- if (parse_nvram(field->format, value, nvram_value, &nvram_len) == NULL) {
- return -3;
+ unsigned int nvram_len = sizeof(nvram_value);
+ if (parse_nvram(format_type, value, nvram_value, &nvram_len) == NULL) {
+ return -2;
}
- if (HMX_NVRAM_SetField(field->nvram_type, 0,
- nvram_value, nvram_len) != DRV_OK) {
- return -4;
+ 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;
+ }
+ DRV_Error er = HMX_NVRAM_Write(HMX_NVRAM_PARTITION_RW, (unsigned char*)name,
+ 0, nvram_value, nvram_len);
+ if (er != DRV_OK) {
+ return -4;
+ }
+ } else {
+ if (HMX_NVRAM_SetField(field->nvram_type, 0,
+ nvram_value, nvram_len) != DRV_OK) {
+ return -5;
+ }
}
return 0;
}
-int hnvram_main(int argc, char * const argv[]) {
+int hnvram_main(int argc, char* const argv[]) {
DRV_Error err;
libupgrade_verbose = 0;
@@ -382,7 +425,7 @@
int b_flag = 0; // binary: output the binary format
char output[NVRAM_MAX_DATA];
int c;
- while ((c = getopt(argc, argv, "dbqrw:")) != -1) {
+ while ((c = getopt(argc, argv, "dbqrnw:k:")) != -1) {
switch(c) {
case 'b':
b_flag = 1;
@@ -390,6 +433,9 @@
case 'q':
q_flag = 1;
break;
+ case 'n':
+ can_add_flag = 1;
+ break;
case 'w':
{
char* duparg = strdup(optarg);
@@ -401,6 +447,17 @@
free(duparg);
}
break;
+ case 'k':
+ {
+ char* duparg = strdup(optarg);
+ if (clear_nvram(duparg) != DRV_OK) {
+ fprintf(stderr, "Unable to remove key %s\n", duparg);
+ free(duparg);
+ exit(1);
+ }
+ free(duparg);
+ }
+ break;
case 'r':
case 'd':
if (op != c) {
@@ -458,7 +515,7 @@
}
#ifndef TEST_MAIN
-int main(int argc, char * const argv[]) {
+int main(int argc, char* const argv[]) {
return hnvram_main(argc, argv);
}
#endif // TEST_MAIN
diff --git a/hnvram/hnvram_test.cc b/hnvram/hnvram_test.cc
index d10a7a1..39f7e4a 100644
--- a/hnvram/hnvram_test.cc
+++ b/hnvram/hnvram_test.cc
@@ -8,9 +8,40 @@
int libupgrade_verbose = 1;
+char* HMX_NVRAM_Read_Data = NULL;
+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) {
+ return DRV_ERR;
+ } else {
+ snprintf((char*)pValue, ulSize, "%s", HMX_NVRAM_Read_Data);
+ *pLen = strlen(HMX_NVRAM_Read_Data);
+ return DRV_OK;
+ }
+}
+
+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);
+ return DRV_OK;
+}
+
+DRV_Error HMX_NVRAM_Remove(HMX_NVRAM_PARTITION_E partition,
+ unsigned char* pName) {
+ if (HMX_NVRAM_Read_Data == NULL) {
+ return DRV_ERR;
+ }
+ HMX_NVRAM_Read_Data = NULL;
+ return DRV_OK;
+}
+
const char* HMX_NVRAM_GetField_Data = NULL;
DRV_Error HMX_NVRAM_GetField(NVRAM_FIELD_T field, unsigned int offset,
- void *data, int nDataSize) {
+ void* data, int nDataSize) {
if (HMX_NVRAM_GetField_Data == NULL) {
return DRV_ERR;
} else {
@@ -23,7 +54,7 @@
int HMX_NVRAM_SetField_Len = -1;
DRV_Error HMX_NVRAM_SetField_Return = DRV_OK;
DRV_Error HMX_NVRAM_SetField(NVRAM_FIELD_T field, unsigned int offset,
- void *data, int nDataSize) {
+ void* data, int nDataSize) {
HMX_NVRAM_SetField_Data = (unsigned char*)malloc(nDataSize);
memcpy(HMX_NVRAM_SetField_Data, data, nDataSize);
HMX_NVRAM_SetField_Len = nDataSize;
@@ -38,12 +69,11 @@
return DRV_OK;
}
-DRV_Error HMX_NVRAM_GetLength(tagNVRAM_FIELD partition, int *pLen) {
+DRV_Error HMX_NVRAM_GetLength(tagNVRAM_FIELD partition, unsigned int* pLen) {
*pLen = HMX_NVRAM_SetField_Len;
return DRV_OK;
}
-
#define TEST_MAIN
#include "hnvram_main.c"
@@ -54,6 +84,7 @@
virtual ~HnvramTest() {}
virtual void SetUp() {
+ HMX_NVRAM_Read_Data = NULL;
HMX_NVRAM_GetField_Data = NULL;
HMX_NVRAM_SetField_Data = NULL;
HMX_NVRAM_SetField_Len = -1;
@@ -70,49 +101,39 @@
TEST_F(HnvramTest, TestFormat) {
char out[256];
- EXPECT_STREQ("foo", format_nvram(HNVRAM_STRING, "foo", 3, out, sizeof(out)));
- EXPECT_STREQ("bar", format_nvram(HNVRAM_STRING, "bar", 3, out, sizeof(out)));
+ EXPECT_STREQ("foo", format_nvram(HNVRAM_STRING, (unsigned char*)"foo", 3,
+ out, sizeof(out)));
+ EXPECT_STREQ("bar", format_nvram(HNVRAM_STRING, (unsigned char*)"bar", 3,
+ out, sizeof(out)));
- char mac[6] = {0x11, 0x22, 0x03, 0x40, 0x55, 0xf6};
+ unsigned char mac[6] = {0x11, 0x22, 0x03, 0x40, 0x55, 0xf6};
EXPECT_STREQ("11:22:03:40:55:f6",
format_nvram(HNVRAM_MAC, mac, sizeof(mac), out, sizeof(out)));
- const char in1[1] = {1};
+ const unsigned char in1[1] = {1};
EXPECT_STREQ("1", format_nvram(HNVRAM_UINT8, in1, sizeof(in1),
out, sizeof(out)));
- const char in254[1] = {0xfe};
+ const unsigned char in254[1] = {0xfe};
EXPECT_STREQ("254", format_nvram(HNVRAM_UINT8, in254, sizeof(in254),
out, sizeof(out)));
- const char vers[] = {0x02, 0x01};
+ const unsigned char vers[] = {0x02, 0x01};
EXPECT_STREQ("1.2", format_nvram(HNVRAM_HMXSWVERS, vers, sizeof(vers),
out, sizeof(out)));
- const char gpn[] = {0x86, 0x0, 0x4, 0x0};
+ const unsigned char gpn[] = {0x86, 0x0, 0x4, 0x0};
EXPECT_STREQ("86000400", format_nvram(HNVRAM_GPN, gpn, sizeof(gpn),
out, sizeof(out)));
- const char hex[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+ const unsigned char hex[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
EXPECT_STREQ("0123456789abcdef", format_nvram(
HNVRAM_HEXSTRING, hex, sizeof(hex), out, sizeof(out)));
}
-TEST_F(HnvramTest, TestGetNvramField) {
- EXPECT_EQ(NULL, get_nvram_field("nosuchfield"));
- EXPECT_EQ(NVRAM_FIELD_SYSTEM_ID, get_nvram_field("SYSTEM_ID")->nvram_type);
-}
-
-TEST_F(HnvramTest, TestReadNvram) {
- char output[256];
- HMX_NVRAM_GetField_Data = "TestSystemId";
- EXPECT_STREQ("SYSTEM_ID=TestSystemId",
- read_nvram("SYSTEM_ID", output, sizeof(output), 0));
-}
-
TEST_F(HnvramTest, TestParse) {
char input[256];
unsigned char output[256];
- int outlen = sizeof(output);
+ unsigned int outlen = sizeof(output);
snprintf(input, sizeof(input), "This is a test.");
EXPECT_TRUE(NULL != parse_nvram(HNVRAM_STRING, input, output, &outlen));
@@ -156,16 +177,114 @@
EXPECT_EQ(0, memcmp(hex, output, outlen));
}
-TEST_F(HnvramTest, TestWriteNvram) {
+TEST_F(HnvramTest, TestGetNvramField) {
+ EXPECT_EQ(NULL, get_nvram_field("nosuchfield"));
+ EXPECT_EQ(NVRAM_FIELD_SYSTEM_ID, get_nvram_field("SYSTEM_ID")->nvram_type);
+}
+
+TEST_F(HnvramTest, TestReadFieldNvram) {
+ char output[256];
+ HMX_NVRAM_GetField_Data = "TestSystemId";
+ EXPECT_STREQ("SYSTEM_ID=TestSystemId",
+ read_nvram("SYSTEM_ID", output, sizeof(output), 0));
+ EXPECT_STREQ("TestSystemId",
+ read_nvram("SYSTEM_ID", output, sizeof(output), 1));
+ HMX_NVRAM_GetField_Data = NULL;
+ EXPECT_EQ(NULL, read_nvram("FAKE_SYSTEM_ID", output, sizeof(output), 1));
+}
+
+TEST_F(HnvramTest, TestReadVariableNvram) {
+ char output[256];
+ HMX_NVRAM_Read_Data = strdup("ABC123");
+ EXPECT_STREQ("TEST_VARIABLE=ABC123",
+ read_nvram("TEST_VARIABLE", output, sizeof(output), 0));
+ 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));
+}
+
+TEST_F(HnvramTest, TestWriteFieldNvram) {
+ // Type integer
char* testdata = strdup("ACTIVATED_KERNEL_NUM=1");
EXPECT_EQ(DRV_OK, write_nvram(testdata));
- unsigned char expected[] = {0x01};
- EXPECT_EQ(0, memcmp(HMX_NVRAM_SetField_Data, expected, sizeof(expected)));
+ 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));
+ 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);
+
+ // Should fail trying to change value of non-exsting field
+ testdata = strdup("FAKE_FIELD=abc123");
+ EXPECT_NE(0, write_nvram(testdata));
free(testdata);
}
-int main(int argc, char **argv) {
+TEST_F(HnvramTest, TestWriteVariableNvram) {
+ 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)));
+
+ // Add new one successfully
+ can_add_flag = 1;
+ EXPECT_EQ(0, write_nvram(keyval));
+ EXPECT_STREQ(val,HMX_NVRAM_Read_Data);
+
+ // Should be able to read value
+ char output[256];
+ EXPECT_STREQ(val, read_nvram(key, output, sizeof(output), 1));
+
+ 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);
+
+ free(key);
+ free(val);
+ free(keyval);
+ free(val2);
+ free(keyval2);
+}
+
+TEST_F(HnvramTest, TestClearNvram) {
+ 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
+ can_add_flag = 1;
+ EXPECT_EQ(0, write_nvram(keyval));
+ EXPECT_STREQ(val, HMX_NVRAM_Read_Data);
+
+ // Should be able to read value
+ char output[256];
+ EXPECT_STREQ(val, read_nvram(key, output, sizeof(output), 1));
+
+ // 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));
+
+ free(key);
+ free(val);
+ free(keyval);
+}
+
+int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/ledpattern/Makefile b/ledpattern/Makefile
index 705a398..ad3456d 100644
--- a/ledpattern/Makefile
+++ b/ledpattern/Makefile
@@ -1,7 +1,7 @@
default:
-PREFIX=/
-BINDIR=$(DESTDIR)$(PREFIX)/bin
+ETCDIR=$(DESTDIR)/etc
+BINDIR=$(DESTDIR)/bin
PYTHON?=python
all:
@@ -9,6 +9,9 @@
install:
mkdir -p $(BINDIR)
cp ledpattern.py $(BINDIR)/ledpattern
+ cp ledtapcode.sh $(BINDIR)/ledtapcode
+ cp ledpatterns $(ETCDIR)/ledpatterns
+ chmod +x $(BINDIR)/ledtapcode
install-libs:
@echo "No libs to install."
diff --git a/ledpattern/ledpatterns b/ledpattern/ledpatterns
new file mode 100644
index 0000000..0b86fb7
--- /dev/null
+++ b/ledpattern/ledpatterns
@@ -0,0 +1,28 @@
+SET_LASER_FAILED_0,P,R,R,R,R
+SET_LASER_FAILED_1,P,R,R,R,B
+SET_LASER_FAILED_2,P,R,R,B,R
+SET_LASER_FAILED_3,P,R,R,B,B
+SET_LASER_FAILED_4,P,R,B,R,R
+SET_LASER_FAILED_5,P,R,B,R,B
+SET_LASER_FAILED_6,P,R,B,B,R
+SET_LASER_FAILED_7,P,R,B,B,B
+SET_LASER_FAILED_8,P,B,R,R,R
+SET_LASER_FAILED_9,P,B,R,R,B
+SET_LASER_FAILED_10,P,B,R,B,R
+SET_LASER_FAILED_11,P,B,R,B,B
+SET_LASER_FAILED_12,P,B,B,R,R
+SET_LASER_FAILED_13,P,B,B,R,B
+SET_LASER_FAILED_14,P,B,B,B,R
+SET_LASER_FAILED_15,P,B,B,B,B
+GPON_INITIAL,P,P,R,R
+GPON_STANDBY,P,P,R,B
+GPON_SERIAL,P,P,B,R
+GPON_RANGING,P,P,B,B
+HALTED,P,R,R
+NO_LASER_CHANNEL,P,R,B
+LOSLOF_ALARM,P,R,P
+OTHER_ALARM,P,B,R
+WAIT_ACS,P,B,B
+ALL_OK,P,B
+UNKNOWN_ERROR,P,R
+
diff --git a/ledpattern/ledtapcode.sh b/ledpattern/ledtapcode.sh
new file mode 100755
index 0000000..7793993
--- /dev/null
+++ b/ledpattern/ledtapcode.sh
@@ -0,0 +1,130 @@
+#!/bin/sh
+
+. /etc/utils.sh
+
+LEDPATTERN="ledpattern /etc/ledpatterns"
+SYSFS_GPON_PATH="/sys/devices/platform/gpon"
+MONITOR_PATH="/tmp/gpio/ledcontrol"
+LASER_STATUS_FILE="/tmp/laser_i2c_status"
+ALARM_GPON_FILE="$SYSFS_GPON_PATH/info/alarmGpon"
+GPON_INFO_FILE="$SYSFS_GPON_PATH/info/infoGpon"
+HALTED_FILE="$MONITOR_PATH/halted"
+HW_FAILURE="$MONITOR_PATH/hardware_failure"
+LASER_CHANNEL_FILE="$SYSFS_GPON_PATH/misc/laserChannel"
+ACS_FILE="$MONITOR_PATH/acsconnected"
+
+PlayPatternAndExit()
+{
+ state="$1"
+ # ledpattern takes care of all the LED management and state selection.
+ result="$($LEDPATTERN $state)"
+ if [ "$?" -ne 0 ]; then
+ echo "Failed to display pattern $state: $result"
+ exit 1
+ fi
+ exit 0
+}
+
+if [ ! -f "$ALARM_GPON_FILE" ]; then
+ echo "$ALARM_GPON_FILE does not exist"
+ PlayPatternAndExit UNKNOWN_ERROR
+fi
+
+if [ ! -f "$GPON_INFO_FILE" ]; then
+ echo "$GPON_INFO_FILE does not exist"
+ PlayPatternAndExit UNKNOWN_ERROR
+fi
+
+if [ ! -f "$LASER_CHANNEL_FILE" ]; then
+ echo "$LASER_CHANNEL_FILE does not exist"
+ PlayPatternAndExit UNKNOWN_ERROR
+fi
+
+# It is a valid state that there may not be a LASER_STATUS_FILE yet.
+if [ -f "$LASER_STATUS_FILE" ]; then
+ laser_status=$(cat "$LASER_STATUS_FILE")
+ if [ "$laser_status" -ne 0 ]; then
+ # Blink out requested laser channel that we failed to tune to
+ laser_channel=$(cat "$LASER_CHANNEL_FILE")
+ if [ "$laser_channel" -eq -1 ]; then
+ echo "$LASER_STATUS_FILE indicates success but there is no requested
+ channel in $LASER_CHANNEL_FILE"
+ PlayPatternAndExit UNKNOWN_ERROR
+ fi
+ echo "Playing SET_LASER_FAILED_${laser_channel} pattern"
+ PlayPatternAndExit "SET_LASER_FAILED_${laser_channel}"
+ fi
+fi
+
+if [ -f "$HW_FAILURE" ]; then
+ echo "Playing HALTED pattern on HW_FAILURE"
+ PlayPatternAndExit HALTED
+fi
+
+if [ -f "$HALTED_FILE" ]; then
+ echo "Playing HALTED pattern on HALTED_FILE"
+ PlayPatternAndExit HALTED
+fi
+
+# Chop the table headers off the output using tail, otherwise grep gets
+# confused later.
+alarm_info=$(cat "$ALARM_GPON_FILE" | tail -n+7)
+los_output=$(echo "$alarm_info" | grep "LOS" | grep "ON")
+lof_output=$(echo "$alarm_info" | grep "LOF" | grep "ON")
+if [ -n "$los_output" ] || [ -n "$lof_output" ]; then
+ echo "Playing LOSLOF_ALARM pattern"
+ PlayPatternAndExit LOSLOF_ALARM
+fi
+other_alarm=$(echo "$alarm_info" | grep "ON")
+if [ -n "$other_alarm" ]; then
+ echo "Playing OTHER_ALARM pattern"
+ PlayPatternAndExit OTHER_ALARM
+fi
+
+gpon_info=$(cat "$GPON_INFO_FILE" | grep "ONU STATE")
+if contains "$gpon_info" "INITIAL"; then
+ echo "Playing GPON_INITIAL pattern"
+ PlayPatternAndExit GPON_INITIAL
+elif contains "$gpon_info" "STANDBY"; then
+ echo "Playing GPON_STANDBY pattern"
+ PlayPatternAndExit GPON_STANDBY
+elif contains "$gpon_info" "SERIAL"; then
+ echo "Playing GPON_SERIAL pattern"
+ PlayPatternAndExit GPON_SERIAL
+elif contains "$gpon_info" "RANGING"; then
+ echo "Playing GPON_RANGING pattern"
+ PlayPatternAndExit GPON_RANGING
+fi
+
+# GFLT110 does not have tuneable laser
+tuneable_laser="false"
+if startswith "$(cat /etc/platform)" "GFLT3"; then
+ tuneable_laser="true"
+fi
+
+if [ "$tuneable_laser" = false ]; then
+ if [ ! -f "$ACS_FILE" ]; then
+ echo "Playing WAIT_ACS pattern"
+ PlayPatternAndExit WAIT_ACS
+ else
+ echo "Playing ALL_OK pattern"
+ PlayPatternAndExit ALL_OK
+ fi
+else
+ laser_channel=$(cat "$LASER_CHANNEL_FILE")
+ if [ ! -f "$ACS_FILE" ] && [ "$laser_channel" -eq "-1" ]; then
+ echo "Playing NO_LASER_CHANNEL pattern"
+ PlayPatternAndExit NO_LASER_CHANNEL
+ elif [ ! -f "$ACS_FILE" ] && [ "$laser_channel" -ne "-1" ]; then
+ echo "Playing WAIT_ACS pattern"
+ PlayPatternAndExit WAIT_ACS
+ elif [ -f "$ACS_FILE" ] && [ "$laser_channel" -eq "-1" ]; then
+ echo "Has ACS but no laser channel"
+ echo "Playing NO_LASER_CHANNEL pattern"
+ PlayPatternAndExit NO_LASER_CHANNEL
+ else
+ echo "Playing ALL_OK pattern"
+ PlayPatternAndExit ALL_OK
+ fi
+fi
+
diff --git a/signing/S99readallfiles b/signing/S99readallfiles
index 87b97e0..00838fa 100755
--- a/signing/S99readallfiles
+++ b/signing/S99readallfiles
@@ -27,8 +27,11 @@
case "$1" in
start)
(
- nice -n 19 readallfiles -q / &&
- clear_failure_count
+ if is-fiberjack; then
+ nice -n 19 readallfiles -q /config && clear_failure_count
+ else
+ nice -n 19 readallfiles -q / && clear_failure_count
+ fi
) 2>&1 | logos readall &
;;
stop)
diff --git a/taxonomy/pcaptest.py b/taxonomy/pcaptest.py
index 2b5d90f..02c2039 100644
--- a/taxonomy/pcaptest.py
+++ b/taxonomy/pcaptest.py
@@ -71,8 +71,10 @@
('iPhone 6/6+', './testdata/pcaps/iPhone 6+ 5GHz.pcap'),
('iPhone 6s/6s+', './testdata/pcaps/iPhone 6s 2.4GHz.pcap'),
('iPhone 6s/6s+', './testdata/pcaps/iPhone 6s+ 2.4GHz.pcap'),
+ ('iPhone 6s/6s+', './testdata/pcaps/iPhone 6s+ 2.4GHz RRM.pcap'),
('iPhone 6s/6s+', './testdata/pcaps/iPhone 6s 5GHz.pcap'),
('iPhone 6s/6s+', './testdata/pcaps/iPhone 6s+ 5GHz.pcap'),
+ ('iPhone 6s/6s+', './testdata/pcaps/iPhone 6s+ 5GHz RRM.pcap'),
('iPod Touch 1st or 2nd gen', './testdata/pcaps/iPod Touch 1st gen 2.4GHz.pcap'),
('Moto G or Moto X', './testdata/pcaps/Moto X 2.4GHz Specific.pcap'),
('Moto G or Moto X', './testdata/pcaps/Moto X 2.4GHz.pcap'),
diff --git a/taxonomy/testdata/dhcp.leases b/taxonomy/testdata/dhcp.leases
index ab83a43..f3eae5e 100644
--- a/taxonomy/testdata/dhcp.leases
+++ b/taxonomy/testdata/dhcp.leases
@@ -69,3 +69,4 @@
1432237016 a4:d1:d2:00:00:00 192.168.42.58 iPaadOldiOS
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+
diff --git a/taxonomy/testdata/dhcp.signatures b/taxonomy/testdata/dhcp.signatures
index 1fcfa61..0c79a18 100644
--- a/taxonomy/testdata/dhcp.signatures
+++ b/taxonomy/testdata/dhcp.signatures
@@ -61,3 +61,4 @@
a4:d1:d2:00:00:00 1,3,6,15,119,252
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
diff --git a/taxonomy/testdata/pcaps/iPhone 6s+ 2.4GHz RRM.pcap b/taxonomy/testdata/pcaps/iPhone 6s+ 2.4GHz RRM.pcap
new file mode 100644
index 0000000..28cbed8
--- /dev/null
+++ b/taxonomy/testdata/pcaps/iPhone 6s+ 2.4GHz RRM.pcap
Binary files differ
diff --git a/taxonomy/testdata/pcaps/iPhone 6s+ 5GHz RRM.pcap b/taxonomy/testdata/pcaps/iPhone 6s+ 5GHz RRM.pcap
new file mode 100644
index 0000000..1ba43ad
--- /dev/null
+++ b/taxonomy/testdata/pcaps/iPhone 6s+ 5GHz RRM.pcap
Binary files differ
diff --git a/wifi/configs.py b/wifi/configs.py
index 743fe10..97a27ce 100644
--- a/wifi/configs.py
+++ b/wifi/configs.py
@@ -375,7 +375,7 @@
utils.validate_and_sanitize_bssid(opt.bssid))
network_block = make_network_block(network_block_lines)
- freq_list = ','.join(autochannel.get_all_frequencies(opt.band))
+ freq_list = ' '.join(autochannel.get_all_frequencies(opt.band))
lines = [
'ctrl_interface=/var/run/wpa_supplicant',
diff --git a/wifi/configs_test.py b/wifi/configs_test.py
index 64e05c6..016fc27 100755
--- a/wifi/configs_test.py
+++ b/wifi/configs_test.py
@@ -11,9 +11,9 @@
_FREQ_LIST = {
- '2.4': '2412,2417,2422,2427,2432,2437,2442,2447,2452,2457,2462',
- '5': ('5180,5200,5220,5240,5745,5765,5785,5805,5825,5260,5280,5300,5320,'
- '5500,5520,5540,5560,5580,5660,5680,5700'),
+ '2.4': '2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462',
+ '5': ('5180 5200 5220 5240 5745 5765 5785 5805 5825 5260 5280 5300 5320 '
+ '5500 5520 5540 5560 5580 5660 5680 5700'),
}
diff --git a/wifi/iw.py b/wifi/iw.py
index ae2a8b6..c0bbf57 100644
--- a/wifi/iw.py
+++ b/wifi/iw.py
@@ -226,14 +226,26 @@
return interface
-def find_all_interfaces_from_phy(phy):
+def find_all_interfaces_from_phy(phy, interface_type=None):
+ """Finds the names of all interfaces on a given phy.
+
+ Args:
+ phy: The name of a phy, e.g. 'phy0'.
+ interface_type: An INTERFACE_TYPE value (optional).
+
+ Returns:
+ A list of all interfaces found.
+ """
interfaces = []
- for interface_type in INTERFACE_TYPE:
+ interface_types = INTERFACE_TYPE
+ if interface_type:
+ interface_types = [interface_type]
+ for interface_type in interface_types:
pattern = re.compile(r'w%s[0-9]\w*\Z' % re.escape(interface_type))
interfaces.extend(interface for interface
in dev_parsed()[phy]['interfaces']
if pattern.match(interface))
- return interfaces
+ return set(interfaces)
def find_interface_from_band(band, interface_type, interface_suffix):
@@ -254,6 +266,23 @@
return find_interface_from_phy(phy, interface_type, interface_suffix)
+def find_all_interfaces_from_band(band, interface_type=None):
+ """Finds the names of all interface on a given band.
+
+ Args:
+ band: The band for which you want the interface.
+ interface_type: An INTERFACE_TYPE value (optional).
+
+ Returns:
+ A list of all interfaces found.
+ """
+ phy = find_phy(band, 'auto')
+ if phy is None:
+ return []
+
+ return find_all_interfaces_from_phy(phy, interface_type)
+
+
def find_width_and_channel(interface):
"""Finds the width and channel being used by a given interface.
diff --git a/wifi/iw_test.py b/wifi/iw_test.py
index 4a7ef4c..2293954 100755
--- a/wifi/iw_test.py
+++ b/wifi/iw_test.py
@@ -514,6 +514,19 @@
@wvtest.wvtest
+def find_all_interfaces_from_phy_test():
+ wvtest.WVPASSEQ(set(['wlan0', 'wlan0_portal', 'wcli0']),
+ iw.find_all_interfaces_from_phy('phy0'))
+ wvtest.WVPASSEQ(set(['wlan0', 'wlan0_portal']),
+ iw.find_all_interfaces_from_phy('phy0', iw.INTERFACE_TYPE.ap))
+ wvtest.WVPASSEQ(set(['wcli0']),
+ iw.find_all_interfaces_from_phy('phy0',
+ iw.INTERFACE_TYPE.client))
+ wvtest.WVPASSEQ(set(['wlan1', 'wlan1_portal']),
+ iw.find_all_interfaces_from_phy('phy1'))
+
+
+@wvtest.wvtest
def find_interface_from_band_test():
wvtest.WVPASSEQ('wlan0',
iw.find_interface_from_band('2.4', iw.INTERFACE_TYPE.ap, ''))
@@ -529,6 +542,19 @@
@wvtest.wvtest
+def find_all_interfaces_from_band_test():
+ wvtest.WVPASSEQ(set(['wlan0', 'wlan0_portal', 'wcli0']),
+ iw.find_all_interfaces_from_band('2.4'))
+ wvtest.WVPASSEQ(set(['wlan0', 'wlan0_portal']),
+ iw.find_all_interfaces_from_band('2.4', iw.INTERFACE_TYPE.ap))
+ wvtest.WVPASSEQ(set(['wcli0']),
+ iw.find_all_interfaces_from_band('2.4',
+ iw.INTERFACE_TYPE.client))
+ wvtest.WVPASSEQ(set(['wlan1', 'wlan1_portal']),
+ iw.find_all_interfaces_from_band('5'))
+
+
+@wvtest.wvtest
def info_parsed_test():
wvtest.WVPASSEQ({
'wdev': '0x3',
diff --git a/wifi/quantenna.py b/wifi/quantenna.py
index 1408574..7aad0d0 100755
--- a/wifi/quantenna.py
+++ b/wifi/quantenna.py
@@ -34,20 +34,27 @@
raise utils.BinWifiException('no VLAN ID for interface %s' % hif)
-def _get_interface(mode, suffix):
+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
# IDs start at 2). The client interface must map to wifi0, so it must have
# VLAN ID 2.
prefix = 'wlan' if mode == 'ap' else 'wcli'
- suffix = '_' + suffix if suffix else ''
+ suffix = r'.*' if suffix == 'ALL' else suffix
for hif in _get_quantenna_interfaces():
- if re.match(prefix + r'\d*' + suffix, 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)
- return hif, lif, mac, vlan
- return None, None, None, None
+ yield hif, lif, mac, vlan
+
+
+def _get_interface(mode, suffix):
+ return next(_get_interfaces(mode, suffix), (None, None, None, None))
+
+
+def _set_link_state(hif, state):
+ subprocess.check_output(['ip', 'link', 'set', 'dev', hif, state])
def _ifplugd_action(hif, state):
@@ -145,6 +152,7 @@
_qcsapi('vlan_config', 'pcie0', 'trunk', vlan)
_qcsapi('block_bss', lif, 0)
+ _set_link_state(hif, 'up')
_ifplugd_action(hif, 'up')
except:
stop_ap_wifi(opt)
@@ -188,6 +196,7 @@
_qcsapi('vlan_config', 'pcie0', 'enable')
_qcsapi('vlan_config', 'pcie0', 'trunk', vlan)
+ _set_link_state(hif, 'up')
_ifplugd_action(hif, 'up')
except:
stop_client_wifi(opt)
@@ -198,34 +207,32 @@
def stop_ap_wifi(opt):
"""Disable AP."""
- hif, lif, _, _ = _get_interface('ap', opt.interface_suffix)
- if not hif:
- return False
+ hif = None
+ for hif, lif, _, _ in _get_interfaces('ap', opt.interface_suffix):
+ try:
+ _qcsapi('wifi_remove_bss', lif)
+ except subprocess.CalledProcessError:
+ pass
- try:
- _qcsapi('wifi_remove_bss', lif)
- except subprocess.CalledProcessError:
- pass
+ _set_link_state(hif, 'down')
+ _ifplugd_action(hif, 'down')
- _ifplugd_action(hif, 'down')
-
- return True
+ return hif is not None
def stop_client_wifi(opt):
"""Disable client."""
- hif, lif, _, _ = _get_interface('sta', opt.interface_suffix)
- if not hif:
- return False
+ hif = None
+ for hif, lif, _, _ in _get_interfaces('sta', opt.interface_suffix):
+ try:
+ _qcsapi('remove_ssid', lif, _qcsapi('get_ssid_list', lif, 1))
+ except subprocess.CalledProcessError:
+ pass
- try:
- _qcsapi('remove_ssid', lif, _qcsapi('get_ssid_list', lif, 1))
- except subprocess.CalledProcessError:
- pass
+ _set_link_state(hif, 'down')
+ _ifplugd_action(hif, 'down')
- _ifplugd_action(hif, 'down')
-
- return True
+ return hif is not None
def scan_wifi(_):
diff --git a/wifi/quantenna_test.py b/wifi/quantenna_test.py
index 177f557..b0fb485 100755
--- a/wifi/quantenna_test.py
+++ b/wifi/quantenna_test.py
@@ -35,7 +35,7 @@
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'),
+ wvtest.WVPASSEQ(quantenna._get_interface('ap', '_portal'),
('wlan0_portal', 'wifi1', '00:00:00:00:00:00', 3))
wvtest.WVPASSEQ(quantenna._get_interface('sta', ''),
(None, None, None, None))
diff --git a/wifi/wifi.py b/wifi/wifi.py
index 8797633..142010c 100755
--- a/wifi/wifi.py
+++ b/wifi/wifi.py
@@ -50,7 +50,7 @@
X,extra-short-timeouts Use shorter key rotations; 1=rotate PTK, 2=rotate often
Y,yottasecond-timeouts Don't rotate any keys: PTK, GTK, or GMK
P,persist For set commands, persist options so we can restore them with 'wifi restore'. For stop commands, remove persisted options.
-S,interface-suffix= Interface suffix []
+S,interface-suffix= Interface suffix (defaults to ALL for stop commands; use NONE to specify no suffix) []
lock-timeout= How long, in seconds, to wait for another /bin/wifi process to finish before giving up. [60]
scan-ap-force (Scan only) scan when in AP mode
scan-passive (Scan only) do not probe, scan passively
@@ -381,18 +381,25 @@
if band == '5' and quantenna.stop_ap_wifi(opt):
continue
- interface = iw.find_interface_from_band(
- band, iw.INTERFACE_TYPE.ap, opt.interface_suffix)
- if interface is None:
- utils.log('No AP interface for %s GHz; nothing to stop', band)
+ interfaces = []
+ if opt.interface_suffix == 'ALL':
+ interfaces = iw.find_all_interfaces_from_band(band, iw.INTERFACE_TYPE.ap)
+ else:
+ interface = iw.find_interface_from_band(
+ band, iw.INTERFACE_TYPE.ap, opt.interface_suffix)
+ if interface:
+ interfaces = [interface]
+ if not interfaces:
+ utils.log('No AP interfaces for %s GHz; nothing to stop', band)
continue
- if _stop_hostapd(interface):
- if opt.persist:
- persist.delete_options('hostapd', band)
- else:
- utils.log('Failed to stop hostapd on interface %s', interface)
- success = False
+ for interface in interfaces:
+ if _stop_hostapd(interface):
+ if opt.persist:
+ persist.delete_options('hostapd', band)
+ else:
+ utils.log('Failed to stop hostapd on interface %s', interface)
+ success = False
return success
@@ -989,18 +996,26 @@
if band == '5' and quantenna.stop_client_wifi(opt):
continue
- interface = iw.find_interface_from_band(
- band, iw.INTERFACE_TYPE.client, opt.interface_suffix)
- if interface is None:
- utils.log('No client interface for %s GHz; nothing to stop', band)
+ interfaces = []
+ if opt.interface_suffix == 'ALL':
+ interfaces = iw.find_all_interfaces_from_band(
+ band, iw.INTERFACE_TYPE.client)
+ else:
+ interface = iw.find_interface_from_band(
+ band, iw.INTERFACE_TYPE.client, opt.interface_suffix)
+ if interface:
+ interfaces = [interface]
+ if not interfaces:
+ utils.log('No client interfaces for %s GHz; nothing to stop', band)
continue
- if _stop_wpa_supplicant(interface):
- if opt.persist:
- persist.delete_options('wpa_supplicant', band)
- else:
- utils.log('Failed to stop wpa_supplicant on interface %s', interface)
- success = False
+ for interface in interfaces:
+ if _stop_wpa_supplicant(interface):
+ if opt.persist:
+ persist.delete_options('wpa_supplicant', band)
+ else:
+ utils.log('Failed to stop wpa_supplicant on interface %s', interface)
+ success = False
return success
@@ -1044,10 +1059,18 @@
parser.fatal('Must specify a command (see usage for details).')
return 1
+ command = extra[0]
+
# set and setclient have a different default for -b.
- if extra[0].startswith('set') and ' ' in opt.band:
+ if command.startswith('set') and ' ' in opt.band:
opt.band = '2.4'
+ if command == 'off' or command.startswith('stop'):
+ if not opt.interface_suffix:
+ opt.interface_suffix = 'ALL'
+ elif opt.interface_suffix == 'NONE':
+ opt.interface_suffix = ''
+
try:
function = {
'set': set_wifi,