Merge "Add ARC specific configure options."
diff --git a/fs/skeleton/bin/apman b/fs/skeleton/bin/apman
index 5623157..4ad90c6 100755
--- a/fs/skeleton/bin/apman
+++ b/fs/skeleton/bin/apman
@@ -53,25 +53,56 @@
 
 # Check all existing command and gateway files, then monitor those as well as
 # access_point files for changes.
-{ cd "$TMP_DIR" && ls gateway.* command.*;
+{ cd "$TMP_DIR" && ls gateway.* command.* subnet.*;
   cd "$CONFIG_DIR" && ls command.*;
   watch-dir $TMP_DIR $CONFIG_DIR; } |
 while read filename; do
+  route_type=
+  if startswith "$filename" "subnet."; then
+    route_type="subnet"
+  fi
   if startswith "$filename" "gateway."; then
+    route_type="gateway"
+  fi
+  if [ "$route_type" != "" ]; then
     filepath="$TMP_DIR/$filename"
     if [ -e "$filepath" ]; then
-      interface=${filename#gateway.}
-      gateway=$(cat "$filepath")
-      # If this script is running as conman's deathrattle, it is possible that
-      # there is a wifi route up too and also that acs_autoprovisioning is
-      # enabled.  Between deleting and re-adding this default route, traffic
-      # could be routed via wifi, and if autoprovisioning is enabled and the
-      # wifi connection is to a neighbor's RG then the ACS could provision this
-      # device to the neighbor.  Removing the file which enables that
-      # autoprovisioning here prevents that from happening.
-      rm -f /tmp/conman/acs_autoprovisioning
-      ip -4 route del default dev "$interface"
-      ip -4 route add default via "$gateway" dev "$interface" $initrwnd
+      interface=${filename#${route_type}.}
+      # Trying to add a default route without a subnet route fails, because
+      # there is no route to the gateway.  So just always update the subnet
+      # route first, and then update the default route if we know the gateway.
+      subnet_filepath="$TMP_DIR/subnet.$interface"
+      if [ -e "$subnet_filepath" ]; then
+        subnet=$(cat "$subnet_filepath")
+        # If this script is running as conman's deathrattle, it is possible that
+        # there is a wifi route up too and also that acs_autoprovisioning is
+        # enabled.  Between deleting and re-adding this default route, traffic
+        # could be routed via wifi, and if autoprovisioning is enabled and the
+        # wifi connection is to a neighbor's RG then the ACS could provision this
+        # device to the neighbor.  Removing the file which enables that
+        # autoprovisioning here prevents that from happening.
+        rm -f /tmp/conman/acs_autoprovisioning
+
+        # Remove all subnet routes on $interface except default, with 'scope
+        # link', then recreate the desired subnet route.
+        ip -4 route show dev "$interface" |
+        while read route junk; do
+          # Ignore the RFC2365 multicast route.
+          if ! startswith "$route" "239"; then
+            if contains "$route" "/"; then
+              ip -4 route del "$route" dev "$interface"
+            fi
+          fi
+        done
+        ip -4 route add "$subnet" dev "$interface" $initrwnd
+
+        gateway_filepath="$TMP_DIR/gateway.$interface"
+        if [ -e "$gateway_filepath" ]; then
+          gateway=$(cat "$gateway_filepath")
+          ip -4 route del default dev "$interface"
+          ip -4 route add default via "$gateway" dev "$interface" $initrwnd
+        fi
+      fi
     fi
     continue
   fi
diff --git a/fs/skeleton/bin/apman.test b/fs/skeleton/bin/apman.test
index 59def8c..8e27b4c 100755
--- a/fs/skeleton/bin/apman.test
+++ b/fs/skeleton/bin/apman.test
@@ -7,6 +7,13 @@
 
 . /etc/utils.sh
 
+runnable mktemp &&
+tmpdir="$(mktemp -d ipapplyXXXXXXXXXX)" ||
+tmpdir="/tmp/ipapply.$$"
+tmpbindir="$tmpdir/test_bin"
+mkdir -p "$tmpdir" && echo "using temp dir $tmpdir"
+mkdir "$tmpbindir"
+
 hostapd_running() {
   pgrep -f '^hostapd .* /tmp/hostapd.conf.wlan.*' >/dev/null
 }
@@ -40,12 +47,13 @@
   fi
 }
 
-wait_route_created() {
-  local interface="$1"
-  local gateway="$2"
+wait_route_changed() {
+  local operation="$1"
+  local route="$2"
+  local interface="$3"
 
-  for x in $(seq 20); do
-    if grep "default" | grep "dev $interface" | grep "via $gateway"; then
+  for x in $(seq 50); do
+    if grep "$operation $route" "$ip_out" | grep "dev $interface"; then
       return 0
     fi
     sleep 0.1
@@ -55,11 +63,24 @@
 }
 
 
+ip_out="$tmpdir/ip.out"
+cat >"$tmpbindir/ip" <<-EOF
+	#!/bin/sh
+	echo test_bin/ip \$@ >>$ip_out
+	if [ "x\$3" = "xshow" -a -e $tmpdir/ip_route_show ]; then
+	  cat $tmpdir/ip_route_show
+	fi
+	exit 0
+EOF
+chmod 777 "$tmpbindir/ip"
+PATH="$tmpbindir:$PATH"
+
+
 echo "Setting up"
 wifi stop
 pkill "apman$"
-rm /config/conman/command*
-rm /config/conman/access_point*
+rm -f /config/conman/command*
+rm -f /config/conman/access_point*
 # Creating wlan0_apmantest sometimes fails if we don't reset wlan0.
 wlan0mac=$(cat /sys/class/net/wlan0/address)
 mac=$(mac_addr_increment $wlan0mac 100)
@@ -70,8 +91,10 @@
 WVPASS iw phy phy0 interface add wlan0_apmantest type __ap
 WVPASS ip link set dev wlan0_apmantest address "$mac"
 
-WVSTART "apman"
+# Start apman.
 apman&
+
+WVSTART "access points"
 WVFAIL hostapd_running
 
 touch /config/conman/access_point.5
@@ -96,14 +119,27 @@
 echo "env\nWIFI_PSK=password\nwifi\nset\n-b\n2.4\n-s\nssid\n-S\n_apmantest" > /config/conman/command._apmantest.2.4
 hostapd_wait_check_running true
 
+WVSTART "route management"
+echo "192.168.1.1" > /tmp/conman/gateway.wlan0_apmantest
+echo "192.168.1.0/24" > /tmp/conman/subnet.wlan0_apmantest
+WVPASS wait_route_changed "add" "default via 192.168.1.1" "wlan0_apmantest"
+WVPASS wait_route_changed "add" "192.168.1.0/24" "wlan0_apmantest"
+
+echo "default via 192.168.1.1 dev wlan0_apmantest" > $tmpdir/ip_route_show
+echo "192.168.1.0/24 dev wlan0_apmantest" >> $tmpdir/ip_route_show
+
+echo "192.168.1.0/16" > /tmp/conman/subnet.wlan0_apmantest
+WVPASS wait_route_changed "del" "default" "wlan0_apmantest"
+WVPASS wait_route_changed "add" "default via 192.168.1.1" "wlan0_apmantest"
+WVPASS wait_route_changed "del" "192.168.1.0/24" "wlan0_apmantest"
+WVPASS wait_route_changed "add" "192.168.1.0/16" "wlan0_apmantest"
+
 
 echo "Cleaning up"
 WVPASS iw dev wlan0_apmantest del
 pkill "apman$"
 wifi off
-rm /config/conman/command*
-rm /config/conman/access_point*
+rm -f /config/conman/command*
+rm -f /config/conman/access_point*
 rm -f /tmp/conman/gateway.br0
-if [ -n "$original_br0_route" ]; then
-  echo "$original_br0_route" | xargs ip route add
-fi
+rm -rf $tmpdir
diff --git a/fs/skeleton/bin/ipapply b/fs/skeleton/bin/ipapply
index b1ab5e1..1b3e0eb 100755
--- a/fs/skeleton/bin/ipapply
+++ b/fs/skeleton/bin/ipapply
@@ -134,17 +134,23 @@
   subprocess.check_call(['ip', 'addr', 'del', ip, 'dev', iface_name])
 
 
-def DefaultRouteAdd(iface_name, routers):
+def RouteAdd(iface_name, routers=None, subnet=None):
   """Set a default route via this interface through apman."""
   # apman supports only a single route, and installs it as 'default'.
   # arbitrarily select the first route if multiple provided.
-  path = os.path.join(TMP_CONMAN_DIR, 'gateway.%s' % iface_name)
+  subnet_path = os.path.join(TMP_CONMAN_DIR, 'subnet.%s' % iface_name)
+  gateway_path = os.path.join(TMP_CONMAN_DIR, 'gateway.%s' % iface_name)
   if routers:
     first_route = routers.split()[0]
     Log('add default route with routers: %r', first_route)
-    with open(path, 'w') as f:
+    with open(gateway_path, 'w') as f:
       f.write(first_route)
 
+  if subnet:
+    Log('add subnet route: %r', subnet)
+    with open(subnet_path, 'w') as f:
+      f.write(subnet)
+
 
 def SelectAndApply(iface_name):
   """Select the config file and apply the contents."""
@@ -187,26 +193,63 @@
     if 'new_ip_address' in ip:
       ip_string = ip['new_ip_address']
       netmask = '32'
-      if 'new_subnet_mask' in ip:
-        netmask = NormalizeNetmask(ip['new_subnet_mask'])
+      if selected_config_file == static_config_file and 'new_subnet_mask' in ip:
+        netmask = str(NormalizeNetmask(ip['new_subnet_mask']))
       ip_string = ip_string + '/' + netmask
       new_ips.add(ip_string)
 
   IpAddrUpdate(iface_name, new_ips)
 
   for ip in config.get('ip', []):
-    if 'new_routers' in ip:
-      DefaultRouteAdd(iface_name, ip['new_routers'])
+    subnet = None
+    if 'new_ip_address' in ip and 'new_subnet_mask' in ip:
+      mask = str(NormalizeNetmask(ip['new_subnet_mask']))
+      subnet = ''.join((ApplyNetmask(ip['new_ip_address'], mask), '/', mask))
+    RouteAdd(iface_name, routers=ip.get('new_routers', None), subnet=subnet)
+
+
+
+def IpToInt(ip):
+  return struct.unpack('!I', socket.inet_pton(socket.AF_INET, ip))[0]
+
+
+def IntToIp(ip):
+  return socket.inet_ntop(socket.AF_INET, struct.pack('!I', ip))
 
 
 def NormalizeNetmask(netmask):
-  if '.' not in netmask:
-    return netmask
+  """Convert a netmask to 'bits', e.g. 24, if it isn't already."""
+  if not isinstance(netmask, basestring):
+    raise ValueError('NormalizeNetmask expects a string')
+
+  if '.' in netmask:
+    return NetmaskToBits(netmask)
+
+  # If we got an invalid string, i.e. one that isn't an IP string (handled
+  # above) or an integer, it will be detected here and a ValueError will be
+  # raised.
+  x = int(netmask)
+  if not 0 <= x <= 32:
+    raise ValueError('Netmask bits should be between 0 and 32')
+
+  return x
+
+
+def NetmaskToBits(netmask):
+  """255.255.255.0' -> 24"""
 
   # '255.255.255.0' -> '11111111111111111111111100000000'
-  netmask_bitstring = bin(struct.unpack('!I', socket.inet_pton(socket.AF_INET,
-                                                               netmask))[0])[2:]
-  return str(len(netmask_bitstring.split('0')[0]))
+  netmask_bitstring = bin(IpToInt(netmask))[2:]
+
+  # '11111111111111111111111100000000' -> 24
+  return len(netmask_bitstring.split('0')[0])
+
+
+def ApplyNetmask(ip, netmask):
+  int_ip = IpToInt(ip)
+  netmask = int(NormalizeNetmask(netmask))
+  int_netmask = (2**netmask - 1) << (32 - netmask)
+  return IntToIp(int_ip & int_netmask)
 
 
 def main():
diff --git a/fs/skeleton/bin/ipapply.test b/fs/skeleton/bin/ipapply.test
index 58df857..ae3f361 100755
--- a/fs/skeleton/bin/ipapply.test
+++ b/fs/skeleton/bin/ipapply.test
@@ -17,6 +17,7 @@
 mkdir -p "$tmpdir"
 cleanup() {
   echo "Temp files:" >&2
+  echo "$(find "$tmpdir")"
   find "$tmpdir" | while read name; do
     # skip dumping the test scripts.
     echo $name | grep "test_bin" >/dev/null && continue
@@ -95,35 +96,44 @@
 
 
 echo "TEST deltas"
-echo "   inet 1.1.1.1/24 brd 255.255.255.0 scope global iface0" >"$tmpdir/ip_addr_show"
-echo "   inet 1.1.1.32/32 brd 255.255.255.255 scope global iface0" >>"$tmpdir/ip_addr_show"
+echo "   inet 1.1.1.1/32 brd 255.255.255.0 scope global iface0" >"$tmpdir/ip_addr_show"
+echo "   inet 1.1.1.2/24 brd 255.255.255.255 scope global iface0" >>"$tmpdir/ip_addr_show"
 output=$(ipapply iface0 2>&1 1>/dev/null)
 WVPASSEQ $? 0
-echo "${output}" | grep "ip addr add 1.1.1.1/24 dev iface0" >/dev/null
+echo "${output}" | grep "ip addr add 1.1.1.1/32 dev iface0" >/dev/null
 WVPASSNE $? 0
-echo "${output}" | grep "ip addr add 1.1.1.32/32 dev iface0" >/dev/null
-WVPASSNE $? 0
+echo "${output}" | grep "ip addr del 1.1.1.2/24 dev iface0" >/dev/null
+WVPASSEQ $? 0
 
 cat >$tmpdir/$STATIC_PATH/iface0 <<-EOF
 	{ "iface0": {
 	  "ip": [  { "new_ip_address": "1.1.1.1", "new_subnet_mask": "24" },
 	           { "new_ip_address": "1.1.1.2", "new_subnet_mask": "24" },
-	           { "new_ip_address": "1.1.1.32" } ]
+	           { "new_ip_address": "1.1.1.4" } ]
 	} }
 EOF
-echo "   inet 1.1.1.3/24 brd 255.255.255.0 scope global iface0" >>"$tmpdir/ip_addr_show"
+echo "   inet 1.1.1.3/32 brd 255.255.255.0 scope global iface0" >>"$tmpdir/ip_addr_show"
 output=$(ipapply iface0 2>&1 1>/dev/null)
 WVPASSEQ $? 0
 echo "${output}" | grep "ip addr add 1.1.1.1/24 dev iface0" >/dev/null
-WVPASSNE $? 0
+WVPASSEQ $? 0
+echo "${output}" | grep "ip addr del 1.1.1.1/32 dev iface0" >/dev/null
+WVPASSEQ $? 0
 echo "${output}" | grep "ip addr add 1.1.1.2/24 dev iface0" >/dev/null
+WVPASSNE $? 0
+echo "${output}" | grep "ip addr del 1.1.1.3/32 dev iface0" >/dev/null
 WVPASSEQ $? 0
-echo "${output}" | grep "ip addr del 1.1.1.3/24 dev iface0" >/dev/null
+echo "${output}" | grep "ip addr add 1.1.1.4/32 dev iface0" >/dev/null
 WVPASSEQ $? 0
-echo "${output}" | grep "ip addr del 1.1.1.32/32 dev iface0" >/dev/null
-WVPASSEQ $? 1
 
-
+subnet_file=$tmpdir/$TMP_CONMAN/subnet.iface0
+WVPASS [ -e $subnet_file ]
+gateway_file=$tmpdir/$TMP_CONMAN/gateway.iface0
+WVFAIL [ -e $gateway_file ]
+expected_file=$tmpdir/expected_file
+echo -n "1.1.1.0/24" >$expected_file
+WVPASS cmp $subnet_file $expected_file
+rm $expected_file
 rm -f $tmpdir/ip_addr_show
 
 
@@ -133,14 +143,15 @@
 mkdir -p $tmpdir/$STATIC_PATH
 cat >$tmpdir/$STATIC_PATH/iface0 <<-EOF
 	{ "iface0": {
-	  "ip": [  { "new_ip_address": "1.1.1.1",
-	             "new_subnet_mask": "255.255.255.0" } ]
+	  "ip": [  { "new_ip_address": "1.1.1.100",
+	             "new_subnet_mask": "255.255.0.0",
+	             "new_routers": "1.1.1.1" } ]
 	} }
 EOF
 
 output=$(ipapply iface0 2>&1 1>/dev/null)
 WVPASSEQ $? 0
-echo "${output}" | grep "ip addr add 1.1.1.1/24 dev iface0" >/dev/null
+echo "${output}" | grep "ip addr add 1.1.1.100/16 dev iface0" >/dev/null
 WVPASSEQ $? 0
 
 
@@ -152,14 +163,23 @@
 	{ "iface0": {
 	  "ip": [  { "new_ip_address": "2.2.2.2",
 	             "new_subnet_mask": "24",
-	             "new_routers": "a.b.c.d" } ]
+	             "new_routers": "2.2.2.1" } ]
 	} }
 EOF
 output=$(ipapply iface0 2>&1 1>/dev/null)
 WVPASSEQ $? 0
-echo "${output}" | grep "ip addr add 1.1.1.1/24 dev iface0" >/dev/null
+echo "${output}" | grep "ip addr add 1.1.1.100/16 dev iface0" >/dev/null
 WVPASSEQ $? 0
-WVPASS [ ! -e $tmpdir/$TMP_CONMAN/gateway.iface0 ]
+subnet_file=$tmpdir/$TMP_CONMAN/subnet.iface0
+WVPASS [ -e $subnet_file ]
+gateway_file=$tmpdir/$TMP_CONMAN/gateway.iface0
+WVPASS [ -e $gateway_file ]
+expected_file=$tmpdir/expected_file
+echo -n "1.1.0.0/16" >$expected_file
+WVPASS cmp $subnet_file $expected_file
+echo -n "1.1.1.1" >$expected_file
+WVPASS cmp $gateway_file $expected_file
+rm $expected_file
 
 echo
 echo "TEST dynamic config"
@@ -169,12 +189,16 @@
 
 output=$(ipapply iface0 2>&1 1>/dev/null)
 WVPASSEQ $? 0
-echo "${output}" | grep "ip addr add 2.2.2.2/24 dev iface0" >/dev/null
+echo "${output}" | grep "ip addr add 2.2.2.2/32 dev iface0" >/dev/null
 WVPASSEQ $? 0
+subnet_file=$tmpdir/$TMP_CONMAN/subnet.iface0
+WVPASS [ -e $subnet_file ]
 gateway_file=$tmpdir/$TMP_CONMAN/gateway.iface0
-expected_file=$tmpdir/expected_gateway
 WVPASS [ -e $gateway_file ]
-echo -n "a.b.c.d" >$expected_file
+expected_file=$tmpdir/expected_file
+echo -n "2.2.2.0/24" >$expected_file
+WVPASS cmp $subnet_file $expected_file
+echo -n "2.2.2.1" >$expected_file
 WVPASS cmp $gateway_file $expected_file
 rm $expected_file
 
@@ -185,16 +209,16 @@
 export IIU_TEST_UP_INTERFACES="br0 wan0"
 cat >$tmpdir/$STATIC_PATH/br0 <<-EOF
 	{ "br0": {
-	  "ip": [  { "new_ip_address": "1.1.1.1",
+	  "ip": [  { "new_ip_address": "1.1.1.2",
 	             "new_subnet_mask": "24",
-	             "new_routers": "nexthop" } ]
+	             "new_routers": "1.1.1.1" } ]
 	} }
 EOF
 cat >$tmpdir/$DYNAMIC_PATH/br0 <<-EOF
 	{ "br0": {
 	  "ip": [  { "new_ip_address": "2.2.2.2",
 	             "new_subnet_mask": "24",
-	             "new_routers": "a.b.c.d" } ]
+	             "new_routers": "2.2.2.1" } ]
 	} }
 EOF
 mkdir -p $tmpdir/sys/class/net/wan0
@@ -202,12 +226,16 @@
 
 output=$(ipapply br0 2>&1 1>/dev/null)
 WVPASSEQ $? 0
-echo "${output}" | grep "ip addr add 1.1.1.1/24 dev br0" >/dev/null
+echo "${output}" | grep "ip addr add 1.1.1.2/24 dev br0" >/dev/null
 WVPASSEQ $? 0
+subnet_file=$tmpdir/$TMP_CONMAN/subnet.br0
+WVPASS [ -e $subnet_file ]
 gateway_file=$tmpdir/$TMP_CONMAN/gateway.br0
 WVPASS [ -e $gateway_file ]
-expected_file=$tmpdir/expected_gateway
-echo -n "nexthop" >$expected_file
+expected_file=$tmpdir/expected_file
+echo -n "1.1.1.0/24" >$expected_file
+WVPASS cmp $subnet_file $expected_file
+echo -n "1.1.1.1" >$expected_file
 WVPASS cmp $gateway_file $expected_file
 rm $expected_file
 
@@ -219,12 +247,17 @@
 
 output=$(ipapply br0 2>&1 1>/dev/null)
 WVPASSEQ $? 0
-echo "${output}" | grep "ip addr add 2.2.2.2/24 dev br0" >/dev/null
+echo "${output}" | grep "ip addr add 2.2.2.2/32 dev br0" >/dev/null
 WVPASSEQ $? 0
+subnet_file=$tmpdir/$TMP_CONMAN/subnet.br0
+WVPASS [ -e $subnet_file ]
 gateway_file=$tmpdir/$TMP_CONMAN/gateway.br0
 WVPASS [ -e $gateway_file ]
-expected_file=$tmpdir/expected_gateway
-echo -n "a.b.c.d" >$expected_file
+expected_file=$tmpdir/expected_file
+echo -n "2.2.2.0/24" >$expected_file
+WVPASS cmp $subnet_file $expected_file
+expected_file=$tmpdir/expected_file
+echo -n "2.2.2.1" >$expected_file
 WVPASS cmp $gateway_file $expected_file
 rm $expected_file
 
@@ -239,13 +272,13 @@
 	{ "iface0": {
 	  "ip": [  { "new_ip_address": "2.2.2.2",
 	             "new_subnet_mask": "24",
-	             "new_routers": "a.b.c.d" } ]
+	             "new_routers": "2.2.2.1" } ]
 	} }
 EOF
-echo "   inet 2.2.2.2/24 brd 255.255.255.0 scope global iface0" >"$tmpdir/ip_addr_show"
+echo "   inet 2.2.2.2/32 brd 255.255.255.0 scope global iface0" >"$tmpdir/ip_addr_show"
 output=$(ipapply iface0 2>&1 1>/dev/null)
 WVPASSEQ $? 0
 echo "${output}" | grep "interface 'iface0' down" >/dev/null
 WVPASSEQ $? 0
-echo "${output}" | grep "ip addr del 2.2.2.2/24 dev iface0" >/dev/null
+echo "${output}" | grep "ip addr del 2.2.2.2/32 dev iface0" >/dev/null
 WVPASSEQ $? 0
diff --git a/fs/skeleton/bin/register_experiment b/fs/skeleton/bin/register_experiment
index b068c85..628f221 100755
--- a/fs/skeleton/bin/register_experiment
+++ b/fs/skeleton/bin/register_experiment
@@ -1,5 +1,5 @@
-#! /bin/sh
-
+#!/bin/sh
+#
 # Tell the experiment subsystem that we support the named system-level
 # (as opposed to catawampus-internal) experiment.
 #
@@ -17,9 +17,14 @@
 # Otherwise the results of A/B tests will end up partially lying, where
 # cwmpd's periodic stats say an experiment is active even though we are using
 # the non-experimental behaviour.
+#
 expname="$1"
-if [ ! -d /tmp -o ! -d /config ]; then
-  # if /tmp or /config is nonexistent then just bail out early.
+if [ ! -w /tmp ]; then
+  echo "WARNING: /tmp not writable: experiment '$expname' cannot activate."
+  exit 0
+fi
+if [ ! -w /config ]; then
+  echo "WARNING: /config not writable: experiment '$expname' cannot activate."
   exit 0
 fi
 
diff --git a/fs/skeleton/etc/init.d/S02nexus.platform_gfibertv b/fs/skeleton/etc/init.d/S02nexus.platform_gfibertv
index 848286a..4ce0b39 100755
--- a/fs/skeleton/etc/init.d/S02nexus.platform_gfibertv
+++ b/fs/skeleton/etc/init.d/S02nexus.platform_gfibertv
@@ -72,11 +72,6 @@
   mkdir -p /tmp/gpio/ledcontrol
   leds 4 0  # blink activity while booting
   echo 30 >/tmp/gpio/fanpercent  # low fan at first
-  if is-secure-boot; then
-    : >/tmp/gpio/ledcontrol/secure_boot
-  else
-    rm -f /tmp/gpio/ledcontrol/secure_boot
-  fi
   ulimit -c 49152
   if runnable gpio-mailbox; then
     reboot-if-fail gpio-mailbox 2>&1 | logos gpio-mailbox &
diff --git a/fs/skeleton/etc/init.d/S08volcheck.platform_gfibertv b/fs/skeleton/etc/init.d/S08volcheck.platform_gfibertv
index a192c46..bf6ae50 100755
--- a/fs/skeleton/etc/init.d/S08volcheck.platform_gfibertv
+++ b/fs/skeleton/etc/init.d/S08volcheck.platform_gfibertv
@@ -24,6 +24,7 @@
 # eMMC support
 DATA_MMC_NAME="data+ext4"
 ATV_DATA_MMC_NAME="userdata"
+ATV_HWCFG_MMC_NAME="hwcfg"
 DRM_FS_NAME="drmfs1"
 DRM_FS_RECOVER_NAME="drmfs2"
 
@@ -195,6 +196,11 @@
   mount -t ext4 -o rw,defaults $1 $2 || return 1
 }
 
+mount_hwcfg_ro()
+{
+  mount -t cramfs -o ro,relatime,barrier=1 $1 $2 || return 1
+}
+
 # $1 : primary drmfs
 # $2 : secondary drmfs
 recover_drmfs()
@@ -300,18 +306,33 @@
     [ ! -d /tmp/oprofile ] && mkdir -p /tmp/oprofile
 
     if has-drm-fs; then
-      DRM_FS_MMC_NO=$(check_mmc ${DRM_FS_NAME})
-      DRM_FS_RECOVER_MMC_NO=$(check_mmc ${DRM_FS_RECOVER_NAME})
-      DRM_FS_BLK_NAME=/dev/mmcblk0p${DRM_FS_MMC_NO}
-      DRM_FS_RECOVER_BLK_NAME=/dev/mmcblk0p${DRM_FS_RECOVER_MMC_NO}
-      if [ -b ${DRM_FS_BLK_NAME} ]; then
-        # create folder for SAGE usage tables if not present
-        [ ! -d /user/widevine/brcm_sage ] && mkdir -p /user/widevine/brcm_sage && chmod 777 /user/widevine/brcm_sage
-        [ ! -d /user/drmfs ] && mkdir -p /user/drmfs
-        if ! mount_drmfs_ro ${DRM_FS_BLK_NAME} /user/drmfs; then
-          echo "DRMFS is corrupt, attempting to recover keybox..."
-          if ! recover_drmfs ${DRM_FS_BLK_NAME} ${DRM_FS_RECOVER_BLK_NAME}; then
-            echo "DRMFS is corrupted and not recoverable."
+      # create folder for SAGE usage tables if not present
+      [ ! -d /user/widevine/brcm_sage ] && mkdir -p /user/widevine/brcm_sage && chmod 777 /user/widevine/brcm_sage
+      [ ! -d /user/drmfs ] && mkdir -p /user/drmfs
+      ATV_HWCFG_MMC_NO=$(check_mmc ${ATV_HWCFG_MMC_NAME})
+      DRMFS_MOUNTED=0 # not mounted yet
+      if [ -n "${ATV_HWCFG_MMC_NO}" ]; then
+        ATV_HWCFG_BLK_NAME=/dev/mmcblk0p${ATV_HWCFG_MMC_NO}
+        echo "Found ATV partition table ${ATV_HWCFG_MMC_NAME} at ${ATV_HWCFG_BLK_NAME}!"
+        if [ -b ${ATV_HWCFG_BLK_NAME} ]; then
+          if mount_hwcfg_ro ${ATV_HWCFG_BLK_NAME} /user/drmfs; then
+            DRMFS_MOUNTED=1
+          else
+            echo "failed mounting ${ATV_HWCFG_BLK_NAME}"
+          fi
+        fi
+      fi
+      if [ ${DRMFS_MOUNTED} -eq 0 ]; then
+        DRM_FS_MMC_NO=$(check_mmc ${DRM_FS_NAME})
+        DRM_FS_RECOVER_MMC_NO=$(check_mmc ${DRM_FS_RECOVER_NAME})
+        DRM_FS_BLK_NAME=/dev/mmcblk0p${DRM_FS_MMC_NO}
+        DRM_FS_RECOVER_BLK_NAME=/dev/mmcblk0p${DRM_FS_RECOVER_MMC_NO}
+        if [ -b ${DRM_FS_BLK_NAME} ]; then
+          if ! mount_drmfs_ro ${DRM_FS_BLK_NAME} /user/drmfs; then
+            echo "DRMFS is corrupt, attempting to recover keybox..."
+            if ! recover_drmfs ${DRM_FS_BLK_NAME} ${DRM_FS_RECOVER_BLK_NAME}; then
+              echo "DRMFS is corrupted and not recoverable."
+            fi
           fi
         fi
       fi
diff --git a/fs/skeleton/etc/init.d/S90media.platform_gfibertv b/fs/skeleton/etc/init.d/S90media.platform_gfibertv
index e1f95a6..7cdcfb6 100755
--- a/fs/skeleton/etc/init.d/S90media.platform_gfibertv
+++ b/fs/skeleton/etc/init.d/S90media.platform_gfibertv
@@ -16,18 +16,6 @@
       # remove detritus from manufacturing
       rm -f /var/media/ManufacturingBurnin.mov
     fi
-    if [ -w /var/media ] && [ ! -f /var/media/.mfgmedia2 ]; then
-      mkdir -p /var/media/pictures/Landscapes
-      cd /usr/lib/media/landscapes/
-      for file in *
-      do
-        cp "$file" /var/media/pictures/Landscapes
-        chown video.video /var/media/pictures/Landscapes/"$file"
-        chmod 666 /var/media/pictures/Landscapes/"$file"
-      done
-
-      echo done >/var/media/.mfgmedia2
-    fi
     ;;
   stop)
     ;;
diff --git a/fs/skeleton/etc/init.d/network b/fs/skeleton/etc/init.d/network
index b8246e3..c09fe78 100755
--- a/fs/skeleton/etc/init.d/network
+++ b/fs/skeleton/etc/init.d/network
@@ -257,11 +257,8 @@
     brctl addif $bridge $x &&
     ip -o -f inet route list dev $x |
     while read dst routeinfo; do
-      if [ "$dst" = "default" ]; then
-        echo "Moving route '$dst' from $x to $bridge" &&
-        ip route del dev $x $dst $routeinfo &&
-        ip route add dev $bridge $dst $routeinfo
-      fi
+      ip route add dev $bridge $dst $routeinfo metric 1 &&
+      ip route del dev $x $dst $routeinfo
     done &&
     ip -o -f inet addr show $x |
     while read a b c ip junk; do
@@ -506,9 +503,6 @@
         /sys/class/net/moca[0-9] \
         /sys/class/net/wlan[0-9]
 
-      add_interfaces_to_bridge br1 \
-        /sys/class/net/wlan[0-9]_portal
-
       add_multicast_route
 
       bridge_up br0
diff --git a/fs/skeleton/etc/init.d/wifi b/fs/skeleton/etc/init.d/wifi
index c4f7500..c7f3284 100755
--- a/fs/skeleton/etc/init.d/wifi
+++ b/fs/skeleton/etc/init.d/wifi
@@ -20,6 +20,7 @@
       iw phy "$phy" interface add "$secondary_interface" type managed
     fi
     ip link set dev "$secondary_interface" address "$mac"
+    brctl addif br1 "$secondary_interface"
   fi
 }
 
diff --git a/fs/skeleton/etc/passwd b/fs/skeleton/etc/passwd
index 5bb7fbe..f592857 100755
--- a/fs/skeleton/etc/passwd
+++ b/fs/skeleton/etc/passwd
@@ -8,7 +8,7 @@
 avahi:x:40:40:Avahi mDNS:/:/dev/null
 nobody:*:99:99:Nobody:/:/dev/null
 dbus:x:102:105::/var/run/dbus:/dev/null
-video:x:200:200:Video User:/var/media:/dev/nul
+video:x:200:200:Video User:/var/media:/dev/null
 appclient:x:201:201:Application User:/:/dev/null
 prism:$1$fufhpwhn$eAwIc7tGVHqELSV1MnPP91:300:300:Prism User:/var/prism:/usr/bin/clish
 nfsnobody:x:65534:65534:Anonymous NFS User:/var/tmp:/dev/null
diff --git a/fs/skeleton/etc/utils.sh b/fs/skeleton/etc/utils.sh
index 4d6cf90..41bb9ba 100644
--- a/fs/skeleton/etc/utils.sh
+++ b/fs/skeleton/etc/utils.sh
@@ -76,7 +76,16 @@
 }
 
 
+setup_mcastcapture_settings() {
+  mkdir -p /rw/sagesrv
+  chmod 770 /rw/sagesrv
+  chown video.video /rw/sagesrv
+  chown video.video /rw/sagesrv/*
+}
+
+
 start_sagesrv() {
+  setup_mcastcapture_settings
   LD_LIBRARY_PATH=/app/sage:/app/sage/lib
   # Start up native streaming server
   VIDEO_UID=$(id -u video)
@@ -96,10 +105,7 @@
 
 
 setup_ads() {
-  mkdir -p /rw/sagesrv
-  chmod 770 /rw/sagesrv
-  chown video.video /rw/sagesrv
-  chown video.video /rw/sagesrv/*
+  setup_mcastcapture_settings
   mkdir -p /var/media/ads
   chmod 770 /var/media/ads
   chown video.video /var/media/ads
@@ -133,6 +139,24 @@
 }
 
 
+start_adscale() {
+  setup_mcastcapture_settings
+  VIDEO_UID=$(id -u video)
+  VIDEO_GID=$(id -g video)
+  # Start up native adscale manager
+  babysit 60 \
+  alivemonitor /tmp/adscalealive 80 10 120 \
+  /app/sage/adscale -U $VIDEO_UID -G $VIDEO_GID 2>&1 | logos adscale 0 20000000 &
+}
+
+
+stop_adscale() {
+  pkillwait -f '([b]abysit.*)(adscale)'
+  pkillwait -x 'adscale'
+  pkillwait -f '([a]livemonitor.*)(adscale)'
+}
+
+
 mac_addr_increment() {
   echo "$1" | (
     IFS=: read m1 m2 m3 m4 m5 m6
diff --git a/fs/skeleton/sbin/dhclient-script b/fs/skeleton/sbin/dhclient-script
index eadd325..02ca34a 100755
--- a/fs/skeleton/sbin/dhclient-script
+++ b/fs/skeleton/sbin/dhclient-script
@@ -327,12 +327,6 @@
 if [ x$old_broadcast_address != x ]; then
   old_broadcast_arg="broadcast $old_broadcast_address"
 fi
-if [ -n "$new_subnet_mask" ]; then
-    new_mask="/$new_subnet_mask"
-fi
-if [ -n "$alias_subnet_mask" ]; then
-    alias_mask="/$alias_subnet_mask"
-fi
 if [ x$IF_METRIC != x ]; then
   metric_arg="metric $IF_METRIC"
 fi
diff --git a/fs/skeleton/sbin/hotplug b/fs/skeleton/sbin/hotplug
index 2a05704..d85c076 100755
--- a/fs/skeleton/sbin/hotplug
+++ b/fs/skeleton/sbin/hotplug
@@ -4,7 +4,6 @@
 exec >/dev/kmsg 2>&1
 
 . /etc/utils.sh
-register_experiment RwFirmware
 
 
 create_client_interface() {
@@ -83,6 +82,7 @@
 
   firmware-add)
     echo "hotplug: sys=$SUBSYSTEM act=$ACTION fw=$FIRMWARE dev=$DEVPATH"
+    register_experiment RwFirmware
     if experiment RwFirmware; then
       load_firmware "/rw/firmware/$FIRMWARE" ||
       load_firmware "/rw/firmware/$(basename "$FIRMWARE")"
diff --git a/package/bcm_common/bcm_common.mk b/package/bcm_common/bcm_common.mk
index ead4183..eb4e02a 100644
--- a/package/bcm_common/bcm_common.mk
+++ b/package/bcm_common/bcm_common.mk
@@ -69,7 +69,7 @@
 URSR_TOP=${BCM_NEXUS_DIR}/.. \
 COMMON_DRM_TOP=${BCM_BSEAV_DIR}/lib/security/common_drm \
 SAGE_SUPPORT=${GOOG_SAGE_SUPPORT} \
-SAGE_SECURE_MODE=1
+SAGE_SECURE_MODE=6
 
 ifeq ($(findstring $(PLAT_NOQUOTES), 97425 97428), $(PLAT_NOQUOTES))
 BCM_MAKE_ENV += WVCDM_VERSION=2.1
diff --git a/package/bluez_utils/S54bluez b/package/bluez_utils/S54bluez
index aa82105..790474d 100755
--- a/package/bluez_utils/S54bluez
+++ b/package/bluez_utils/S54bluez
@@ -80,7 +80,7 @@
     # Start BlueZ stack
     (
       echo "$0: Starting btmon"
-      babysit 30 btmon -t 2>&1 | logos btmon &
+      babysit 30 btmon -A -t 2>&1 | logos btmon &
       sleep 1
 
       echo "$0: Starting bluetoothd"
diff --git a/package/gmp/gmp-0001-arc-assembly-fixup.patch b/package/gmp/gmp-0001-arc-assembly-fixup.patch
new file mode 100644
index 0000000..2260be3
--- /dev/null
+++ b/package/gmp/gmp-0001-arc-assembly-fixup.patch
@@ -0,0 +1,24 @@
+--- a/longlong.h	2016-09-01 16:07:44.441547780 -0700
++++ b/longlong.h	2016-09-01 16:11:44.573385451 -0700
+@@ -410,17 +410,17 @@
+ 	   : "=r" (sh),							\
+ 	     "=&r" (sl)							\
+ 	   : "r"  ((USItype) (ah)),					\
+-	     "rIJ" ((USItype) (bh)),					\
++	     "r"  ((USItype) (bh)),					\
+ 	     "%r" ((USItype) (al)),					\
+-	     "rIJ" ((USItype) (bl)))
++	     "r"  ((USItype) (bl)))
+ #define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+   __asm__ ("sub.f\t%1, %4, %5\n\tsbc\t%0, %2, %3"			\
+ 	   : "=r" (sh),							\
+ 	     "=&r" (sl)							\
+ 	   : "r" ((USItype) (ah)),					\
+-	     "rIJ" ((USItype) (bh)),					\
++	     "r" ((USItype) (bh)),					\
+ 	     "r" ((USItype) (al)),					\
+-	     "rIJ" ((USItype) (bl)))
++	     "r" ((USItype) (bl)))
+ #endif
+ 
+ #if defined (__arm__) && W_TYPE_SIZE == 32
diff --git a/package/google/google_gcm/S94gfcm b/package/google/google_gcm/S94gfcm
new file mode 100644
index 0000000..92ed28c
--- /dev/null
+++ b/package/google/google_gcm/S94gfcm
@@ -0,0 +1,34 @@
+#! /bin/sh
+
+start_gfcm() {
+  # start up client router of gcm
+  GCM_ID_DIR=/tmp/gfcm
+  if [ ! -d ${GCM_ID_DIR} ]; then
+    mkdir -p ${GCM_ID_DIR}
+  fi
+
+  babysit 60 /app/gcm/clientrouter \
+    --gcmIdsPath=${GCM_ID_DIR}/gcmIds 2>&1 | logos gfcm 0 20000000 &
+}
+
+stop_gfcm() {
+  # stop client router of gcm
+  pkillwait -f '([b]abysit.*)(clientrouter)'
+  pkillwait -x 'clientrouter'
+}
+
+case "$1" in
+  start)
+    start_gfcm
+    ;;
+  stop)
+    stop_gfcm
+    ;;
+  restart)
+    $0 stop; $0 start
+    ;;
+  *)
+    echo "Usage: $0 {start|stop|restart}"
+    exit 1
+    ;;
+esac
diff --git a/package/google/google_gcm/google_gcm.mk b/package/google/google_gcm/google_gcm.mk
index 532edf1..f02efef 100644
--- a/package/google/google_gcm/google_gcm.mk
+++ b/package/google/google_gcm/google_gcm.mk
@@ -38,6 +38,8 @@
 		INSTALL="$(INSTALL)" \
 		TARGET_DIR="$(TARGET_DIR)" \
 		STRIPCMD="$(STRIPCMD)"
+	$(INSTALL) -m 0755 -D package/google/google_gcm/S94gfcm \
+		$(TARGET_DIR)/etc/init.d/S94gfcm
 endef
 
 define GOOGLE_GCM_CLEAN_CMDS
diff --git a/package/google/google_miniclient/S96mpserver b/package/google/google_miniclient/S96mpserver
index d8be502..e636852 100755
--- a/package/google/google_miniclient/S96mpserver
+++ b/package/google/google_miniclient/S96mpserver
@@ -13,6 +13,11 @@
       export SAGEBIN_PATH=/usr/lib/sage_firmware
       babysit 10 mcnmp_server 2>&1 | logos mcnmp_server 0 20000000 &
       wait-until-created /tmp/nexus_multiprocess
+      if is-secure-boot; then
+        : >/tmp/gpio/ledcontrol/secure_boot
+      else
+        rm -f /tmp/gpio/ledcontrol/secure_boot
+      fi
       nice babysit 60 irmon 2>&1 | logos irmon &
     ) &
     ;;
diff --git a/package/google/google_miniclient/run-app b/package/google/google_miniclient/run-app
index b0b6912..8148232 100755
--- a/package/google/google_miniclient/run-app
+++ b/package/google/google_miniclient/run-app
@@ -60,7 +60,9 @@
     export PATH=$PWD:$PATH
     export sw_picture_decode=y
     chmod 755 /user/netflix/nrd
-    verify_drm_state
+    if ! has-secure-video-path; then
+      verify_drm_state
+    fi
     if verify_playready; then
       echo "Playready state verified."
     else
diff --git a/package/google/google_oregano/S95marjoram b/package/google/google_oregano/S95marjoram
index 05a46c4..779b766 100755
--- a/package/google/google_oregano/S95marjoram
+++ b/package/google/google_oregano/S95marjoram
@@ -30,6 +30,7 @@
     pkillwait -x chsrv &
     stop_sagesrv
     stop_adsmgr
+    stop_adscale
     wait
     ;;
   restart)
diff --git a/package/google/google_platform/Config.in b/package/google/google_platform/Config.in
index 99f378b..a1b81e9 100644
--- a/package/google/google_platform/Config.in
+++ b/package/google/google_platform/Config.in
@@ -24,8 +24,6 @@
 	select BR2_PACKAGE_LIBJSONCPP
 	select BR2_PACKAGE_GPERF
 	select BR2_PACKAGE_PY_TORNADO
-	select BR2_PACKAGE_MICROPYTHON
-	select BR2_PACKAGE_MICROPYTHON_LIB
 	help
 	  This package is a placeholder that depends on other packages needed
 	  to run the Google Fiber devices.
@@ -239,15 +237,11 @@
 	select BR2_PACKAGE_GOOGLE_DASHPLAYER
 	select BR2_PACKAGE_GOOGLE_DIAL
 	select BR2_PACKAGE_GOOGLE_DVBCAPTURE
-	select BR2_PACKAGE_GOOGLE_FREETYPEJNI
 	select BR2_PACKAGE_GOOGLE_GFRM200
-	select BR2_PACKAGE_GOOGLE_IMAGELOADJNI
-	select BR2_PACKAGE_GOOGLE_JTUX
 	select BR2_PACKAGE_GOOGLE_LIBGEP
 	select BR2_PACKAGE_GOOGLE_LICENSES if BR2_mipsel
 	select BR2_PACKAGE_GOOGLE_MEDIA
 	select BR2_PACKAGE_GOOGLE_MINICLIENT
-	select BR2_PACKAGE_GOOGLE_MOBILE_API
 	select BR2_PACKAGE_GOOGLE_MPEGPARSER
 	select BR2_PACKAGE_GOOGLE_OOKLA if BR2_mipsel
 	select BR2_PACKAGE_GOOGLE_OREGANO
@@ -260,6 +254,8 @@
 	select BR2_PACKAGE_BCM_NETFLIX if BR2_mipsel
 	select BR2_PACKAGE_BCM_VUDU if BR2_mipsel
 	select BR2_PACKAGE_IFPLUGD
+	select BR2_PACKAGE_JPEG
+	select BR2_PACKAGE_LIBPNG
 	select BR2_PACKAGE_LIBPROJECTM
 	select BR2_PACKAGE_BOOST
 	select BR2_PACKAGE_AVAHI
diff --git a/package/google/google_pullreader/google_pullreader.mk b/package/google/google_pullreader/google_pullreader.mk
index bb5333d..9c144b3 100644
--- a/package/google/google_pullreader/google_pullreader.mk
+++ b/package/google/google_pullreader/google_pullreader.mk
@@ -20,4 +20,9 @@
         $(INSTALL) -D -m 0644 $(@D)/lib/pullreader.h $(STAGING_DIR)/usr/local/include/
 endef
 
+define HOST_GOOGLE_PULLREADER_INSTALL_CMDS
+	$(INSTALL) -D -m 0644 $(@D)/lib/pullreader.h $(HOST_DIR)/usr/include/
+endef
+
 $(eval $(call GENTARGETS))
+$(eval $(call GENTARGETS,host))
diff --git a/package/google/google_sageserver/S95sageserver b/package/google/google_sageserver/S95sageserver
index 0052876..897b978 100755
--- a/package/google/google_sageserver/S95sageserver
+++ b/package/google/google_sageserver/S95sageserver
@@ -25,6 +25,7 @@
   pkillwait -x 'runsage|chsrv|siege|java'
   stop_sagesrv
   stop_adsmgr
+  stop_adscale
 }
 
 case "$1" in
diff --git a/package/google/google_sageserver/runsage b/package/google/google_sageserver/runsage
index ce69550..9222f6f 100755
--- a/package/google/google_sageserver/runsage
+++ b/package/google/google_sageserver/runsage
@@ -50,6 +50,7 @@
 if [ "$MODE" = "server" ]; then
   start_sagesrv
   start_adsmgr
+  start_adscale
 
   # Cleanup any Oregano files if they switched
   /app/oregano/dogcatcher.sh &
diff --git a/package/libevent/libevent.mk b/package/libevent/libevent.mk
index 76fb627..eb7f45f 100644
--- a/package/libevent/libevent.mk
+++ b/package/libevent/libevent.mk
@@ -3,9 +3,9 @@
 # libevent
 #
 #############################################################
-LIBEVENT_VERSION = 2.0.14
+LIBEVENT_VERSION = 2.0.22
 LIBEVENT_SOURCE = libevent-$(LIBEVENT_VERSION)-stable.tar.gz
-LIBEVENT_SITE = https://github.com/downloads/libevent/libevent
+LIBEVENT_SITE = https://github.com/libevent/libevent/releases/download/release-$(LIBEVENT_VERSION)-stable
 
 LIBEVENT_AUTORECONF = NO
 LIBEVENT_INSTALL_STAGING = YES
diff --git a/package/python-crypto/Config.in b/package/python-crypto/Config.in
index 79f676d..dc8ccc1 100644
--- a/package/python-crypto/Config.in
+++ b/package/python-crypto/Config.in
@@ -1,7 +1,6 @@
 config BR2_PACKAGE_PYTHON_CRYPTO
 	bool "python-crypto"
 	depends on BR2_PACKAGE_PYTHON
-	select BR2_PACKAGE_GMP
 	help
 	  python-crypto is a Python crypto library.
 
diff --git a/package/simpleramfs/mounts-root b/package/simpleramfs/mounts-root
index b38f2c1..bdcd8c4 100755
--- a/package/simpleramfs/mounts-root
+++ b/package/simpleramfs/mounts-root
@@ -150,7 +150,8 @@
               autoconf dns0_ip dns1_ip junk
       [ -z "$device" ] && device=eth0
       if [ "$ip" != "auto" ]; then
-        ifconfig "$device" "$client_ip"
+        ifconfig "$device" "$client_ip" netmask 255.255.255.255
+        route add -net "$gw_ip" netmask 255.255.255.255 dev "$device"
       fi
     }
     log "  IP initialized."
diff --git a/package/toolbox/toolbox-no-ifconfig.patch b/package/toolbox/toolbox-no-ifconfig.patch
new file mode 100644
index 0000000..aa0863c
--- /dev/null
+++ b/package/toolbox/toolbox-no-ifconfig.patch
@@ -0,0 +1,28 @@
+From 0fbe056f9c65cbcf73da96453de97f50b829bfa5 Mon Sep 17 00:00:00 2001
+From: Richard Frankel <rofrankel@google.com>
+Date: Thu, 11 Aug 2016 20:14:23 -0400
+Subject: [PATCH] Remove toolbox ifconfig symlink.
+
+toybox creates /sbin/ifconfig and toolbox creates /bin/ifconfig.  We
+want the toybox one.
+
+Change-Id: Ic98cb37f8ae794477f351c1840e22592786f6d87
+---
+ Makefile | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/Makefile b/Makefile
+index d533563..ad1875a 100644
+--- a/Makefile
++++ b/Makefile
+@@ -11,7 +11,6 @@ TOOLS := \
+ 	insmod \
+ 	rmmod \
+ 	lsmod \
+-	ifconfig \
+ 	setconsole \
+ 	rm \
+ 	mkdir \
+-- 
+2.8.0.rc3.226.g39d4020
+
diff --git a/package/trousers/Config.in b/package/trousers/Config.in
new file mode 100644
index 0000000..f0d266a
--- /dev/null
+++ b/package/trousers/Config.in
@@ -0,0 +1,7 @@
+config BR2_PACKAGE_TROUSERS
+  bool "trousers"
+  depends on BR2_PACKAGE_OPENSSL
+  help
+    The open-source TCG Software Stack.
+
+    http://trousers.sourceforge.net/
diff --git a/package/trousers/trousers-no-metrics.patch b/package/trousers/trousers-no-metrics.patch
new file mode 100644
index 0000000..ddd976c
--- /dev/null
+++ b/package/trousers/trousers-no-metrics.patch
@@ -0,0 +1,125 @@
+diff -r -U 10 a/src/tcsd/Makefile.am b/src/tcsd/Makefile.am
+--- a/src/tcsd/Makefile.am	2016-08-10 07:50:21.000000000 -0700
++++ b/src/tcsd/Makefile.am	2016-08-31 21:03:45.044116933 -0700
+@@ -1,16 +1,16 @@
+ sbin_PROGRAMS=tcsd
+ 
+ BASE_VER ?= 307740
+ 
+ tcsd_CFLAGS=-DAPPID=\"TCSD\" -DVAR_PREFIX=\"@localstatedir@\" -DETC_PREFIX=\"@sysconfdir@\" -I${top_srcdir}/src/include -fPIE -DPIE
+-tcsd_LDADD=${top_builddir}/src/tcs/libtcs.a ${top_builddir}/src/tddl/libtddl.a -lpthread @CRYPTOLIB@ -lmetrics-$(BASE_VER)
++tcsd_LDADD=${top_builddir}/src/tcs/libtcs.a ${top_builddir}/src/tddl/libtddl.a -lpthread @CRYPTOLIB@
+ tcsd_LDFLAGS=-pie -Wl,-z,relro -Wl,-z,now
+ 
+ tcsd_SOURCES=svrside.c tcsd_conf.c tcsd_threads.c platform.c
+ 
+ if TSS_BUILD_PS
+ tcsd_CFLAGS+=-DTSS_BUILD_PS
+ endif
+ if TSS_BUILD_PCR_EVENTS
+ tcsd_CFLAGS+=-DTSS_BUILD_PCR_EVENTS
+ endif
+diff -r -U 10 a/src/tddl/tddl.c b/src/tddl/tddl.c
+--- a/src/tddl/tddl.c	2016-08-10 07:50:21.000000000 -0700
++++ b/src/tddl/tddl.c	2016-08-31 21:06:48.839232975 -0700
+@@ -12,22 +12,20 @@
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <stdio.h>
+ #include <errno.h>
+ #include <string.h>
+ #include <sys/ioctl.h>
+ 
+ #include "trousers/tss.h"
+ #include "trousers_types.h"
+ #include "linux/tpm.h"
+-#include "metrics/c_metrics_library.h"
+-#include "tcs_utils.h"
+ #include "tcslog.h"
+ #include "tddl.h"
+ 
+ struct tpm_device_node tpm_device_nodes[] = {
+ 	{"/dev/tpm0", TDDL_UNDEF, TDDL_UNDEF},
+ 	{"/udev/tpm0", TDDL_UNDEF, TDDL_UNDEF},
+ 	{"/dev/tpm", TDDL_UNDEF, TDDL_UNDEF},
+ 	{NULL, 0, 0}
+ };
+ 
+@@ -156,37 +154,28 @@
+ 	opened_device = NULL;
+ 
+ 	return TSS_SUCCESS;
+ }
+ 
+ TSS_RESULT
+ Tddli_TransmitData(BYTE * pTransmitBuf, UINT32 TransmitBufLen, BYTE * pReceiveBuf,
+ 		   UINT32 * pReceiveBufLen)
+ {
+ 	int sizeResult;
+-	UINT16 request_tag;
+-	TSS_RESULT result;
+-	static CMetricsLibrary metrics_library_handle = NULL;
+-	TSS_BOOL is_auth;
+ 
+ 	if (TransmitBufLen > TDDL_TXBUF_SIZE) {
+ 		LogError("buffer size handed to TDDL is too large! (%u bytes)", TransmitBufLen);
+ 		return TDDLERR(TDDL_E_FAIL);
+ 	}
+ 
+ 	memcpy(txBuffer, pTransmitBuf, TransmitBufLen);
+ 	LogDebug("Calling write to driver");
+-	/* Low-level intercept of errors returned by the TPM for
+-	 * statistical purposes.
+-	 */
+-	request_tag = Decode_UINT16(txBuffer);
+-	is_auth = (request_tag == 0xc2) || (request_tag == 0xc3);
+ 
+ 	if (use_in_socket) {
+ 		Tddli_Close();
+ 		if (Tddli_Open())
+ 			return TDDLERR(TDDL_E_IOERROR);
+ 	}
+ 
+ 	switch (opened_device->transmit) {
+ 		case TDDL_UNDEF:
+ 			/* fall through */
+@@ -234,39 +223,20 @@
+ 
+ 	if ((unsigned)sizeResult > *pReceiveBufLen) {
+ 		LogError("read %d bytes from device %s, (only room for %d)", sizeResult,
+ 				opened_device->path, *pReceiveBufLen);
+ 		return TDDLERR(TDDL_E_INSUFFICIENT_BUFFER);
+ 	}
+ 
+ 	*pReceiveBufLen = sizeResult;
+ 
+ 	memcpy(pReceiveBuf, txBuffer, *pReceiveBufLen);
+-	/* TPM returned a valid response packet into txBuffer.  Extract result
+-	 * code and ship stats.
+-	 */
+-	result = Decode_UINT32(pReceiveBuf + 6);
+-	if (metrics_library_handle == NULL) {
+-		metrics_library_handle = CMetricsLibraryNew();
+-		if (metrics_library_handle != NULL)
+-			CMetricsLibraryInit(metrics_library_handle);
+-	}
+-	if (metrics_library_handle != NULL) {
+-		CMetricsLibrarySendSparseToUMA(metrics_library_handle,
+-					       "Platform.TPM.ErrorCode",
+-					       result);
+-		if (is_auth)
+-			CMetricsLibrarySendSparseToUMA(
+-				metrics_library_handle,
+-				"Platform.TPM.AuthErrorCode",
+-				result);
+-	}
+ 	return TSS_SUCCESS;
+ }
+ 
+ TSS_RESULT
+ Tddli_GetStatus(UINT32 ReqStatusType, UINT32 *pStatus)
+ {
+ 	return TDDLERR(TSS_E_NOTIMPL);
+ }
+ 
+ TSS_RESULT
diff --git a/package/trousers/trousers.mk b/package/trousers/trousers.mk
new file mode 100644
index 0000000..1c365cb
--- /dev/null
+++ b/package/trousers/trousers.mk
@@ -0,0 +1,58 @@
+#############################################################
+#
+## trousers
+#
+##############################################################
+TROUSERS_VERSION = 71d4fee1dc6db9bd22f6866571895b753f222ff5
+TROUSERS_SITE = https://chromium.googlesource.com/chromiumos/third_party/trousers
+TROUSERS_SITE_METHOD = git
+TROUSERS_AUTORECONF = YES
+TROUSERS_INSTALL_STAGING = YES
+TROUSERS_INSTALL_TARGET = YES
+TROUSERS_INSTALL_STAGING_OPT = DESTDIR=$${STAGING_DIR} all
+TROUSERS_INSTALL_TARGET_OPT = DESTDIR=$${TARGET_DIR} all
+TROUSERS_UNINSTALL_STAGING_OPT = DESTDIR=$${STAGING_DIR} clean
+TROUSERS_UNINSTALL_TARGET_OPT = DESTDIR=$${TARGET_DIR} clean
+
+define TROUSERS_INSTALL_STAGING_CMDS
+	$(INSTALL) -d $(STAGING_DIR)/usr/include/tss/
+	$(INSTALL) -m 0644 -t $(STAGING_DIR)/usr/include/tss/ $(@D)/src/include/tss/*
+	$(INSTALL) -d $(STAGING_DIR)/usr/include/trousers/
+	$(INSTALL) -m 0644 -t $(STAGING_DIR)/usr/include/trousers/ $(@D)/src/include/trousers/*
+	$(INSTALL) -D -m 0755 $(@D)/src/tspi/.libs/libtspi.so.1.2.0 \
+		$(STAGING_DIR)/usr/lib/
+	ln -fs libtspi.so.1.2.0 \
+		$(STAGING_DIR)/usr/lib/libtspi.so.1
+	ln -fs libtspi.so.1 \
+		$(STAGING_DIR)/usr/lib/libtspi.so
+endef
+
+define TROUSERS_INSTALL_TARGET_CMDS
+	$(INSTALL) -D -m 0755 $(@D)/src/tcsd/tcsd \
+		$(TARGET_DIR)/usr/bin/
+	$(INSTALL) -D -m 0755 $(@D)/dist/tcsd.conf \
+		$(TARGET_DIR)/etc/
+	$(INSTALL) -D -m 0755 $(@D)/src/tspi/.libs/libtspi.so.1.2.0 \
+		$(TARGET_DIR)/usr/lib/
+	ln -fs libtspi.so.1.2.0 \
+		$(TARGET_DIR)/usr/lib/libtspi.so.1
+	$(INSTALL) -D -m 0755 $(@D)/src/tspi/.libs/libtspi.a \
+		$(TARGET_DIR)/usr/lib/
+endef
+
+define TROUSERS_UNINSTALL_STAGING_CMDS
+	$(RM) -r $(STAGING_DIR)/usr/include/trousers/
+	$(RM) -r $(STAGING_DIR)/usr/include/tss/
+	$(RM) $(STAGING_DIR)/usr/lib/libtspi.so.1.2.0
+	$(RM) $(STAGING_DIR)/usr/lib/libtspi.so.1
+	$(RM) $(STAGING_DIR)/usr/lib/libtspi.so
+endef
+
+define TROUSERS_UNINSTALL_TARGET_CMDS
+	$(RM) $(TARGET_DIR)/usr/bin/tcsd
+	$(RM) $(TARGET_DIR)/etc/tcsd.conf
+	$(RM) $(TARGET_DIR)/usr/lib/libtspi.so.1.2.0
+	$(RM) $(TARGET_DIR)/usr/lib/libtspi.so.1
+endef
+
+$(eval $(call AUTOTARGETS))
diff --git a/package/util-linux/util-linux-fdisk-0001-add-arc-architecture.patch b/package/util-linux/util-linux-fdisk-0001-add-arc-architecture.patch
new file mode 100644
index 0000000..5ef366e
--- /dev/null
+++ b/package/util-linux/util-linux-fdisk-0001-add-arc-architecture.patch
@@ -0,0 +1,12 @@
+--- a/fdisk/fdiskbsdlabel.h	2016-09-01 12:06:32.555493245 -0700
++++ b/fdisk/fdiskbsdlabel.h	2016-09-01 12:07:48.688709127 -0700
+@@ -48,7 +48,8 @@
+ 
+ #if defined (i386) || defined (__sparc__) || defined (__arm__) || \
+     defined (__mips__) || defined (__s390__) || defined (__sh__) || \
+-    defined(__x86_64__) || defined (__avr32__) || defined(__cris__)
++    defined(__x86_64__) || defined (__avr32__) || defined(__cris__) || \
++    defined(__arc__)
+ #define BSD_LABELSECTOR   1
+ #define BSD_LABELOFFSET   0
+ #elif defined (__alpha__) || defined (__powerpc__) || defined (__ia64__) || defined (__hppa__)
diff --git a/scripts/flasher.py b/scripts/flasher.py
index 007b98c..eb7ab5f 100755
--- a/scripts/flasher.py
+++ b/scripts/flasher.py
@@ -1,16 +1,10 @@
 #!/usr/bin/python2.7
 """stream update images to gfiber devices."""
 
-import BaseHTTPServer
 import glob
 import os
-import re
-import shutil
-import SocketServer
 import subprocess
 import sys
-import threading
-import urlparse
 
 
 import options
@@ -27,77 +21,6 @@
 global_serve_map = {}
 
 
-class ImageHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
-  """Handle HTTP requests for images."""
-
-  # pylint:disable=invalid-name
-  def do_GET(self):
-    """Handle GET requests."""
-    f = self.SendHead()
-    if f:
-      shutil.copyfileobj(f, self.wfile)
-      f.close()
-
-  # pylint:disable=invalid-name
-  def do_HEAD(self):
-    """Handle HEAD requests. Required by Handler interface, may not be used."""
-    f = self.SendHead()
-    if f:
-      f.close()
-
-  def SendHead(self):
-    """Send headers and return fd to requested file."""
-    path = urlparse.urlparse(self.path)[2]
-    head, tail = os.path.split(path)
-    if head != '/':
-      self.send_error(404, 'File not found')
-      return None
-    elif tail not in global_serve_map:
-      self.send_error(404, 'File not found')
-      return None
-    else:
-      try:
-        f = open(global_serve_map[tail], 'rb')
-      except IOError:
-        self.send_error(404, 'File not found')
-        return None
-
-    self.send_response(200)
-    self.send_header('Content-type', 'application/octet-stream')
-    fs = os.fstat(f.fileno())
-    self.send_header('Content-length', str(fs.st_size))
-    self.end_headers()
-    return f
-
-
-def ServeImages():
-  handler = ImageHTTPRequestHandler
-  httpd = SocketServer.TCPServer(('', 0), handler)
-  httpd_thread = threading.Thread(target=httpd.serve_forever)
-  httpd_thread.start()
-  return httpd
-
-
-def GetServerIP(remote_ip):
-  unused_iface = ''
-  iface_addr = ''
-  for line in subprocess.check_output(['ip', 'addr']).splitlines():
-    iface_match = re.match(r'\d+: ([a-z0-9]+):', line)
-    if iface_match:
-      unused_iface = iface_match.group(1)
-      iface_addr = ''
-      continue
-
-    addr_match = re.match(r'\s+inet6? (.*?)/\d+ ', line)
-    if addr_match:
-      addr = addr_match.group(1)
-      if not iface_addr:
-        iface_addr = addr
-
-      if addr == remote_ip:
-        return iface_addr
-
-
 def FindImages(basedir):
   """Find our Buildroot directory, then return paths to all its images."""
   if not basedir:
@@ -143,49 +66,37 @@
     o.fatal('must supply at least one host to flash')
 
   global_serve_map, latest_map = FindImages(opt.basedir)
-  try:
-    httpd = ServeImages()
 
-    for host in extra:
-      host_ssh = ['ssh', '-o RequestTTY=no', 'root@%s' % host]
-      # Note: these are 'remote' and 'local' from the perspective of the
-      # destination server, not us, so we are 'remote' here.
-      host_parms = subprocess.check_output(
-          # the leading space in echo's arg is required since /etc/version may
-          # lack a trailing newline, depending on the build.
-          host_ssh + ['cat /etc/version; echo " $SSH_CONNECTION"'])
+  for host in extra:
+    host_ssh = ['ssh', '-o RequestTTY=no', 'root@%s' % host]
 
-      # discard remote_port, local_ip, local_port from $SSH_CONNECTION
-      current_version, remote_ip = host_parms.split()[:2]
-      host_platform, unused_host_build = current_version.split('-', 1)
-      server_ip = GetServerIP(remote_ip)
+    current_version = subprocess.check_output(
+        host_ssh + ['cat /etc/version'])
+    host_platform, unused_host_build = current_version.split('-', 1)
 
-      if opt.image:
-        image_file = os.path.basename(opt.image)
-        requested_version = os.path.splitext(image_file)[0]
-        unused_platform, build = requested_version.split('-', 1)
+    if opt.image:
+      image_file = os.path.basename(opt.image)
+      requested_version = os.path.splitext(image_file)[0]
+      unused_platform, build = requested_version.split('-', 1)
 
-        image = '%s-%s.gi' % (host_platform, build)
-        if image not in global_serve_map:
-          global_serve_map[image] = opt.image
-      else:
-        image = latest_map[host_platform]
+      image = '%s-%s.gi' % (host_platform, build)
+      if image not in global_serve_map:
+        global_serve_map[image] = opt.image
+    else:
+      image = latest_map[host_platform]
 
-      if image == '%s.gi' % current_version and not opt.force:
-        print >> sys.stderr, ('Skipping host %s, already running version %s' %
-                              (host, current_version))
-        print >> sys.stderr, 'Run again with --force to override this.'
-        continue
+    if image == '%s.gi' % current_version and not opt.force:
+      print >> sys.stderr, ('Skipping host %s, already running version %s' %
+                            (host, current_version))
+      print >> sys.stderr, 'Run again with --force to override this.'
+      continue
 
-      image_url = 'http://%s:%d/%s' % (server_ip, httpd.server_address[1],
-                                       image)
-      install_cmd = ('ginstall -t %s && ' % image_url +
-                     'echo "Installed image successfully; rebooting" && '
-                     '( sleep 1; reboot; ) &')
+    install_cmd = ('ginstall -t - && '
+                   'echo "Installed image successfully; rebooting" && '
+                   '( sleep 1; reboot; ) &')
 
-      subprocess.check_call(host_ssh + [install_cmd])
-  finally:
-    httpd.shutdown()
+    image_file = open(global_serve_map[image])
+    subprocess.check_call(host_ssh + [install_cmd], stdin=image_file)
 
 
 if __name__ == '__main__':