Merge "Only set the pbits for the tagged WAN interface."
diff --git a/configs/gftv100_defconfig b/configs/gftv100_defconfig
index 59cde1a..d864b3b 100644
--- a/configs/gftv100_defconfig
+++ b/configs/gftv100_defconfig
@@ -115,6 +115,8 @@
 BR2_PACKAGE_BCM_BLUETOOTH_FW=y
 BR2_PACKAGE_BCM_DRIVERS=y
 BR2_PACKAGE_BCM_DRIVER_MOCA=y
+BR2_PACKAGE_BCM_DRIVER_WIFI=y
+BR2_PACKAGE_BCM_MIRACAST=y
 BR2_PACKAGE_BACKPORTS=y
 BR2_PACKAGE_BACKPORTS_DEFCONFIG="gftv100_defconfig"
 BR2_TARGET_ROOTFS_SQUASHFS=y
diff --git a/configs/gftv200_defconfig b/configs/gftv200_defconfig
index 0993abc..77d8575 100644
--- a/configs/gftv200_defconfig
+++ b/configs/gftv200_defconfig
@@ -118,7 +118,6 @@
 BR2_PACKAGE_BCM_BLUETOOTH_FW=y
 BR2_PACKAGE_BCM_DRIVERS=y
 BR2_PACKAGE_BCM_DRIVER_MOCA2=y
-BR2_PACKAGE_BCM_DRIVER_WIFI_USB=y
 BR2_PACKAGE_BACKPORTS=y
 BR2_PACKAGE_BACKPORTS_DEFCONFIG="gftv200_defconfig"
 BR2_PACKAGE_FIRMWARE=y
diff --git a/fs/simpleramfs/Config.in b/fs/simpleramfs/Config.in
index 7f2f73b..df4fabf 100644
--- a/fs/simpleramfs/Config.in
+++ b/fs/simpleramfs/Config.in
@@ -6,6 +6,7 @@
 	select BR2_PACKAGE_UTIL_LINUX
 	select BR2_PACKAGE_MTD
 	select BR2_PACKAGE_LVM2
+	select BR2_PACKAGE_UTIL_LINUX_MOUNT
 	depends on !BR2_TARGET_ROOTFS_INITRAMFS
 	help
 	  Generate the simplest possible initramfs for finding,
diff --git a/fs/simpleramfs/mounts-root b/fs/simpleramfs/mounts-root
index 5b59881..f2513de 100755
--- a/fs/simpleramfs/mounts-root
+++ b/fs/simpleramfs/mounts-root
@@ -79,6 +79,17 @@
   [ "${1#"$2"}" != "$1" ]
 }
 
+# From the verity command line, gets the hash start in Bytes!
+get_hashstart() {
+  local hashstart=${6#hashstart=}
+  hashstart=$((hashstart * 512))
+  echo "$hashstart"
+}
+
+# Echo back the verity args, but with hashstart=0 for the loopback device.
+clear_hashstart() {
+  echo "$1 $2 $3 $4 $5 hashstart=0 $7 $8 $9"
+}
 
 # host:path format in root= means we should do an NFS root
 if [ "${ROOTDEV#*:/}" != "$ROOTDEV" ]; then
@@ -143,32 +154,45 @@
       ubi_mtd=$(find_mtd "rootfs")
       [ -n "$ubi_mtd" ] || (cat /proc/mtd; die "no mtd named 'rootfs'")
       ROOTDEV=/dev/mtdblock$ubi_mtd
-      KERNELDEV=/dev/mtdblock$(find_mtd "$KERNELNAME")
+      VERITY_CHAR_DEV=/dev/mtd$(find_mtd "$KERNELNAME")
     elif [ -e "$mmcraw" ]; then
       log "Found root='$ROOTDEV': $mmcraw"
       ROOTDEV=$mmcraw
-      KERNELDEV=/dev/mmcblk0p$(find_mmc "$KERNELNAME")
+      VERITYDEV=/dev/mmcblk0p$(find_mmc "$KERNELNAME")
     elif [ -e "$mmcvfat" ]; then
+      # TODO(jnewlin): Remove this after verifying vfat is not used.
       log "Found root='$ROOTDEV': $mmcvfat"
       mount -t vfat -o ro,nodev,noexec,nosuid "$mmcvfat" /vfat
-      KERNELDEV=/dev/loop0
+      VERITYDEV=/dev/loop0
       ROOTDEV=/dev/loop1
-      losetup $KERNELDEV /vfat/vmlinuz.img
+      losetup $VERITYDEV /vfat/vmlinuz.img
       losetup $ROOTDEV /vfat/rootfs.img
     else
       cat /proc/mtd
       log "root='$ROOTDEV' is not an mtd device."
     fi
-    args=$(readverity $KERNELDEV)
+    if [ -n "$VERITY_CHAR_DEV" ]; then
+      # dump the verity header, and read the verity settings, they are stored
+      # in the first 4096 bytes of the image.
+      mount -t tmpfs none /veritytmp
+      nanddump -f /veritytmp/verity.args -l 4096 -s 0 "$VERITY_CHAR_DEV"
+      args=$(readverity /veritytmp/verity.args)
+      hash_size=$(readverity -s /veritytmp/verity.args)
+      rm /veritytmp/verity.args
+      hash_offset=$(get_hashstart $args)
+      args=$(clear_hashstart $args)
+      nanddump -f /veritytmp/hash.dat -l "$hash_size" -s "$hash_offset" "$VERITY_CHAR_DEV"
+      VERITYDEV=/dev/loop3
+      losetup $VERITYDEV /veritytmp/hash.dat
+    else
+      args=$(readverity $VERITYDEV)
+    fi
     args=$(replacefirst "$args" ROOT_DEV "$ROOTDEV")
-    args=$(replacefirst "$args" HASH_DEV "$KERNELDEV")
+    args=$(replacefirst "$args" HASH_DEV "$VERITYDEV")
     if ! dmsetup create -r vroot --table "$args"; then
       veritynote=
-      # TODO(apenwarr): fix uboot, then remove special case for armplatform.
       read x y armplatform platform junk </proc/cpuinfo
-      if [ "$platform" = "BCM7425B0" \
-          -o "$platform" = "BCM7429B0" \
-          -o "$armplatform" = "ARMv7" ]; then
+      if [ "$platform" = "BCM7425B0" ]; then
         log 'dmsetup failed: platform is unsigned device, continuing anyway.'
         SQUASHFS=$ROOTDEV
       else
diff --git a/fs/simpleramfs/simpleramfs.mk b/fs/simpleramfs/simpleramfs.mk
index f780020..a2fd968 100644
--- a/fs/simpleramfs/simpleramfs.mk
+++ b/fs/simpleramfs/simpleramfs.mk
@@ -42,7 +42,7 @@
 
 define SIMPLERAMFS_BUILD_CMDS
 	rm -rf $(@D)/fs
-	for d in sbin bin lib proc dev sys rootfs mnt tmp vfat; do \
+	for d in sbin bin lib proc dev sys rootfs mnt tmp vfat veritytmp; do \
 		mkdir -p $(@D)/fs/$$d; \
 	done
 
@@ -75,6 +75,7 @@
 	ln -f $(TARGET_DIR)/bin/dash $(@D)/fs/bin/sh
 	ln -f 	$(TARGET_DIR)/bin/toolbox \
 		$(TARGET_DIR)/bin/toybox \
+		$(TARGET_DIR)/usr/sbin/nanddump \
 		$(TARGET_DIR)/usr/sbin/ubiattach \
 		$(TARGET_DIR)/usr/sbin/ubidetach \
 		$(TARGET_DIR)/usr/sbin/dmsetup \
diff --git a/fs/skeleton/bin/affinity b/fs/skeleton/bin/affinity
deleted file mode 100755
index 95f7ed7..0000000
--- a/fs/skeleton/bin/affinity
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/sh
-
-echo "warning: please use taskset instead of affinity"
-
-if [ -z "$2" ]; then
-	echo " usage: affinity <pid> <cpu_mask>"
-	exit 1
-fi
-
-exec taskset -p $2 $1
diff --git a/fs/skeleton/bin/run-tlsdate b/fs/skeleton/bin/run-tlsdate
index ce6f508..76c3d92 100755
--- a/fs/skeleton/bin/run-tlsdate
+++ b/fs/skeleton/bin/run-tlsdate
@@ -77,13 +77,39 @@
 }
 
 
+alarm()
+{
+  echo setting alarm
+  alarmfired=0
+  local mypid=$$
+  (sleep $1 && kill -USR1 $mypid) >/dev/null 2>&1 &
+  alarm_pid=$!
+}
+
+disable_alarm() {
+  pkill -9 $alarm_pid
+}
+
+onusr1()
+{
+  echo alarm fired, killing tlsdate.
+  alarmfired=1
+  pkill -9 tlsdate
+}
+
 do_tlsdate()
 {
   echo "trying host '$1'"
+  trap onusr1 USR1
+  alarm 60
   tlsdate -V -v \
       --timewarp --leap \
       -C /etc/ssl/certs/ca-certificates.crt \
       -H "$1"
+  local status=$?
+  disable_alarm
+  if [ $alarmfired = 1 ]; then return 1; fi
+  return $status
 }
 
 
diff --git a/fs/skeleton/bin/try_taskset b/fs/skeleton/bin/try_taskset
new file mode 100755
index 0000000..11db92f
--- /dev/null
+++ b/fs/skeleton/bin/try_taskset
@@ -0,0 +1,9 @@
+#!/bin/sh
+affinity=$1
+shift
+if taskset "$affinity" true 2>/dev/null; then
+  exec taskset "$affinity" "$@"
+else
+  echo "try_taskset: note: affinity '$affinity' unavailable, used default." >&2
+  exec "$@"
+fi
diff --git a/fs/skeleton/bin/wifi.platform_gfibertv b/fs/skeleton/bin/wifi.platform_gfibertv
index 2fc0e8d..c87b919 100755
--- a/fs/skeleton/bin/wifi.platform_gfibertv
+++ b/fs/skeleton/bin/wifi.platform_gfibertv
@@ -169,12 +169,16 @@
 iw_start_hostapd() {
   ifc=$1
   pidfile=/tmp/hostapd.pid.$ifc
-  opts="-d"
+  opts=""
   pkillwait -f "hostapd $opts /tmp/hostapd.conf.$ifc"
   killpid "$pidfile"
   rm -f "$pidfile"
-  babysit 60 startpid "$pidfile" \
-      hostapd $opts "/tmp/hostapd.conf.$ifc" \
+  babysit 10 \
+      startpid "$pidfile" \
+      alivemonitor "/tmp/hostapd.$ifc.alive" 30 2 65 \
+      hostapd $opts \
+      -A "/tmp/hostapd.$ifc.alive" \
+      "/tmp/hostapd.conf.$ifc" \
       2>&1 | logos "hostapd-$ifc" &
 
   # Wait for hostapd to start, and return an error if it doesn't
@@ -593,13 +597,11 @@
   ht20=
   ht40=
   ht_rxstbc=
-  uapsd=
   vht_settings=
 
   phyinfo=$(IW phy "$phy" info 2>/dev/null)
   # non-ieee80211 drivers like mwifiex don't support iw phy phy# info
   [ -z "$phyinfo" ] && phyinfo=$(IW list)
-  contains "$phyinfo" "AP-side u-APSD" && uapsd="uapsd_advertisement_enabled=1"
   contains "$phyinfo" "RX STBC 3-stream" && ht_rxstbc="[RX-STBC123]"
   contains "$phyinfo" "RX STBC 2-stream" && ht_rxstbc="[RX-STBC12]"
   contains "$phyinfo" "RX STBC 1-stream" && ht_rxstbc="[RX-STBC1]"
@@ -607,7 +609,13 @@
   [ -n "$allow_n" ] && enable_80211n="ieee80211n=1" && ht20="[HT20]"
   if [ -n "$allow_ac" ]; then
     [ "$width" = 80 ] && enable_80211ac="ieee80211ac=1"
-    startswith "$band" 5 && ampdu="[MAX-A-MPDU-LEN-EXP4]"
+    contains "$phyinfo" "Maximum RX AMPDU length 16383 bytes" && ampdu="[MAX-A-MPDU-LEN-EXP1]"
+    contains "$phyinfo" "Maximum RX AMPDU length 32767 bytes" && ampdu="[MAX-A-MPDU-LEN-EXP2]"
+    contains "$phyinfo" "Maximum RX AMPDU length 65535 bytes" && ampdu="[MAX-A-MPDU-LEN-EXP3]"
+    contains "$phyinfo" "Maximum RX AMPDU length 131071 bytes" && ampdu="[MAX-A-MPDU-LEN-EXP4]"
+    contains "$phyinfo" "Maximum RX AMPDU length 262143 bytes" && ampdu="[MAX-A-MPDU-LEN-EXP5]"
+    contains "$phyinfo" "Maximum RX AMPDU length 524287 bytes" && ampdu="[MAX-A-MPDU-LEN-EXP6]"
+    contains "$phyinfo" "Maximum RX AMPDU length 1048575 bytes" && ampdu="[MAX-A-MPDU-LEN-EXP7]"
   fi
   [ -n "$allow_ab$allow_g" ] || require_ht="require_ht=1"
   [ -n "$allow_ab$allow_g$allow_n" ] || require_vht="require_vht=1"
@@ -630,6 +638,7 @@
     40) ht40="[HT40+]" ;;
     80) ht40="[HT40+]"
         vht_settings=$(cat <<-EOF
+		vht_capab=$ampdu
 		vht_oper_chwidth=1
 
 		# Wifi channel numbers define the center of a 20 MHz
@@ -660,12 +669,10 @@
 	$enable_80211n
 	$enable_80211ac
 	$enable_wmm
-	$uapsd
 	$require_ht
 	$require_vht
 	$hidden
 	ht_capab=$ht20$ht40$guard_interval$ht_rxstbc
-	vht_capab=$ampdu
 	$vht_settings
 	EOF
   )
diff --git a/fs/skeleton/etc/init.d/S02nexus.platform_gfibertv b/fs/skeleton/etc/init.d/S02nexus.platform_gfibertv
index 572fa5d..464438a 100755
--- a/fs/skeleton/etc/init.d/S02nexus.platform_gfibertv
+++ b/fs/skeleton/etc/init.d/S02nexus.platform_gfibertv
@@ -68,17 +68,6 @@
 hnvram -br HDCP_KEY >/tmp/hdcp_key.tmp
 [ -s /tmp/hdcp_key.tmp ] && mv /tmp/hdcp_key.tmp /tmp/hdcp_key
 
-if [ "$PLATFORM" = GFHD200 ]; then
-  wait-until-created /tmp/gpio/ready
-  if [ "$GPN" = "72001970-01" ]; then
-    # Older units, USB0_PWRON_N is active high
-    brcmgpio -p 106 -h
-  else
-    # newer units, USB0_PWRON_N is active low
-    brcmgpio -p 106 -l
-  fi
-fi
-
 if startswith "$PLATFORM" GFRG2; then
   # Mindspeed-based devices can't fall back to GFP_DMA because they
   # use the GFP_DMA area for CONFIG_COMCERTO_ZONE_DMA_NCNB.  Thus, we
diff --git a/fs/skeleton/etc/init.d/S09drivers.platform_gfibertv b/fs/skeleton/etc/init.d/S09drivers.platform_gfibertv
index 7cf11fa..599926f 100755
--- a/fs/skeleton/etc/init.d/S09drivers.platform_gfibertv
+++ b/fs/skeleton/etc/init.d/S09drivers.platform_gfibertv
@@ -2,37 +2,6 @@
 
 MODULE_PATH=/usr/lib/modules
 
-has_usb_wifi() {
-  for x in /sys/bus/usb/devices/*; do
-    # fields from the USB descriptor to identify the device
-    [ -f $x/idProduct ] && product=$(cat $x/idProduct)
-    [ -f $x/idVendor ] && vendor=$(cat $x/idVendor)
-    if [ "$product" = bd17 ] && [ "$vendor" = 0a5c ]; then
-      echo 'bcm43236-nofirmware'
-      return
-    fi
-    if [ "$product" = 0bdc ] && [ "$vendor" = 0a5c ]; then
-      echo 'bcm43236'
-      return
-    fi
-  done
-}
-
-# Set up WLAN, if present
-if [ "$(has_usb_wifi)" = 'bcm43236-nofirmware' ]; then
-  # reset the chip, AON_GPIO_015
-  brcmgpio -a 15 -l
-  usleep 10000
-  brcmgpio -a 15 -h
-  usleep 10000
-
-  # push its firmware to it
-  bcmdl /lib/firmware/bcm43236-nohotplug.bin
-fi
-if [ ! -z "$(has_usb_wifi)" ]; then
-  [ -e ${MODULE_PATH}/bcm_dbus.ko ] && insmod ${MODULE_PATH}/bcm_dbus.ko
-fi
-# Broadcom PCIe Wifi modules do not require bcmdl nor bcm_dbus.ko.
 [ -e ${MODULE_PATH}/wl.ko ] && insmod ${MODULE_PATH}/wl.ko
 
 # Set up BT, if present
diff --git a/fs/skeleton/etc/init.d/S40network.platform_gfibertv b/fs/skeleton/etc/init.d/S40network.platform_gfibertv
index 67de662..903e8bf 100755
--- a/fs/skeleton/etc/init.d/S40network.platform_gfibertv
+++ b/fs/skeleton/etc/init.d/S40network.platform_gfibertv
@@ -2,56 +2,90 @@
 . /etc/utils.sh
 
 
+irq_affinity() {
+  local irq="$1" cpu="$2"
+  if [ -e "/proc/irq/$irq/smp_affinity" ]; then
+    echo "$cpu" >"/proc/irq/$irq/smp_affinity"
+  else
+    echo "  ...irq #$irq not present, skipping" >&2
+  fi
+}
+
+
 redistribute_irqs()
 {
-  if is-storage-box; then
-    # Storage Box serves MoCA and Ethernet simultaneously,
-    # so we move them to different CPUs.
-    # TV Box mostly uses MoCA *or* Ethernet, and keeps
-    # CPU1 free to handle the video interrupts.
+  # if a second CPU isn't available, do nothing.
+  echo "distribute IRQ handling between cores"
+  if ! taskset 2 true 2>/dev/null; then
+    echo "  ...only one CPU available, skipped."
+  fi
+
+  # Rule of thumb:
+  #  - interrupts are generally by default on first CPU (bitfield=1)
+  #  - let's move realtime sensitive stuff to second CPU (bitfield=2)
+  #  - non-realtime userspace processes can default to both (bitfield=3)
+  if is-storage-box || is-network-box; then
+    # Storage box serves MoCA and ethernet simultaneously.
+    # - put them both on separate CPUs to maximize throughput.
+    # - consider ethernet (not MoCA) to be realtime sensitive, since it
+    #   carries the multicast feed.
+    # - consider disk to be non-realtime, since it can prefetch/writeback.
+    serialcpu=1
+    eth0cpu=2
     mocacpu=1
-    eth0cpu=2
+    wificpu=1  # may not actually have wifi
+    diskcpu=1
   else
-    mocacpu=2
-    eth0cpu=2
+    # TV box handles video interrupts (via miniclient) and
+    # (ethernet *or* MoCA) traffic (which carries the video stream), and wifi.
+    # Network traffic includes the video stream, but it's TCP, so it should
+    # be able to retransmit if packets are lost (unlike multicast on the
+    # storage box) so it should be okay to put it on the non-realtime CPU.
+    serialcpu=1
+    eth0cpu=1
+    mocacpu=1
+    wificpu=1
+    diskcpu=1  # doesn't actually have a disk
   fi
 
-  wifi_irq=
   if grep -q BCM7425 /proc/cpuinfo; then
-    echo 1 >/proc/irq/62/smp_affinity
-    echo $eth0cpu >/proc/irq/18/smp_affinity
-    echo $eth0cpu >/proc/irq/19/smp_affinity
-    echo $mocacpu >/proc/irq/20/smp_affinity
-    echo $mocacpu >/proc/irq/21/smp_affinity
-    echo $mocacpu >/proc/irq/31/smp_affinity
-    wifi_irq=34
+    irq_affinity 62 $serialcpu
+    irq_affinity 18 $eth0cpu
+    irq_affinity 19 $eth0cpu
+    irq_affinity 20 $mocacpu
+    irq_affinity 21 $mocacpu
+    irq_affinity 31 $mocacpu
+    irq_affinity 34 $wificpu  # bcm wifi, if present
+    irq_affinity 42 $diskcpu
   elif grep -q BCM7429 /proc/cpuinfo; then
-    echo 1 >/proc/irq/52/smp_affinity
-    echo $eth0cpu >/proc/irq/16/smp_affinity
-    echo $eth0cpu >/proc/irq/17/smp_affinity
-    echo $mocacpu >/proc/irq/18/smp_affinity
-    echo $mocacpu >/proc/irq/19/smp_affinity
-    echo $mocacpu >/proc/irq/28/smp_affinity
-    wifi_irq=57
+    irq_affinity 52 $serialcpu
+    irq_affinity 16 $eth0cpu
+    irq_affinity 17 $eth0cpu
+    irq_affinity 18 $mocacpu
+    irq_affinity 19 $mocacpu
+    irq_affinity 28 $mocacpu
+    # Wifi is on one of mmc0 or mmc1, but it has varied between early
+    # device models.  Since mmc is pretty fast and seldom used (and we happen
+    # to want it on the non-realtime cpu anyway, like wifi), let's just
+    # blindly put them both on the wifi cpu.
+    irq_affinity 35 $wificpu  # mmc1
+    irq_affinity 36 $wificpu  # mmc0
+    # Note: no disk present, ignore $diskcpu
   elif grep -q comcerto /proc/iomem; then
-    # C2K default is 0x3, allowing IRQ to go to either CPU 0 or 1,
-    # but the result is all IRQs go to CPU0. Steer a few to CPU1.
-    pfe_irq=36
-    ahci_irq=48
-    i2c_irq=62
-    moca_irq=77
-    echo 2 >/proc/irq/$pfe_irq/smp_affinity
-    echo 2 >/proc/irq/$ahci_irq/smp_affinity
-    echo 2 >/proc/irq/$i2c_irq/smp_affinity
-    echo 2 >/proc/irq/$moca_irq/smp_affinity
-  fi
-
-  if has_wifi && is-tv-box && [ ! -z  ${wifi_irq} ]; then
-    # Partial fix for "micro-stuttering" seen in video playback.
-    # Wifi driver needs to be on cpu1 and video on cpu0 so that wifi
-    # can't lock out scheduling of the video player.
-    echo "forcing wifi onto cpu1"
-    echo 2 >/proc/irq/${wifi_irq}/smp_affinity
+    # TODO(apenwarr): we steer *all* PFE network traffic to $eth0cpu.
+    #  Ideally we want only multicast to go there, and other traffic to
+    #  go to the non-realtime CPU.  There may be some way to do this by
+    #  changing PFE somehow.  As is, incoming WAN traffic destined for wifi
+    #  could end up sucking all available CPU and interfere with multicast.
+    irq_affinity  59 $serialcpu  # serial
+    irq_affinity  62 $serialcpu  # i2c (NOR flash)
+    irq_affinity  36 $eth0cpu    # *all* PFE
+    irq_affinity  77 $mocacpu
+    irq_affinity 128 $wificpu    # new boards, ath10k
+    irq_affinity 160 $wificpu    # new boards, ath9k
+    irq_affinity  96 $wificpu  2>/dev/null  # old boards, ath10k
+    irq_affinity 164 $wificpu  2>/dev/null  # old boards, ath9k
+    irq_affinity  48 $diskcpu
   fi
 }
 
@@ -123,6 +157,20 @@
     # configure loopback
     ifup lo
 
+    # Set the wifi mac address from values in hnvram.
+    if [ -e /sys/class/net/wlan0 ]; then
+      a=$(hnvram -qr MAC_ADDR_WIFI)
+      if [ -n "$a" ]; then
+        ip link set wlan0 address "$a"
+      fi
+    fi
+    if [ -e /sys/class/net/wlan1 ]; then
+      a=$(hnvram -qr MAC_ADDR_WIFI2)
+      if [ -n "$a" ]; then
+        ip link set wlan1 address "$a"
+      fi
+    fi
+
     echo -n "Creating bridge... "
     brctl addbr br0 || exit 1
     brctl setfd br0 1
@@ -197,7 +245,6 @@
     echo "Bringing up the bridge..."
     ifup br0
 
-    echo "distribute IRQ handling between cores"
     redistribute_irqs
 
     if [ -e /dev/bmoca0 ]; then
@@ -205,12 +252,6 @@
       babysit 30 runmoca 2>&1 | logos mocad &
     fi
 
-    if ! is-network-box; then
-      # Avoid b/14248601 when talking to GFRG1x0 (or any other
-      # upstream IGMP snooping router, really).
-      sysctl -w net.ipv4.conf.all.force_igmp_version=2
-    fi
-
     if [ -e /sys/class/net/wan0 ]; then
       echo "Bringing up the WAN port..."
       ip link add link wan0 name wan0.2 type vlan id 2
diff --git a/fs/skeleton/etc/init.d/S41igmpworkaround.platform_gfibertv b/fs/skeleton/etc/init.d/S41igmpworkaround.platform_gfibertv
new file mode 100755
index 0000000..87f556c
--- /dev/null
+++ b/fs/skeleton/etc/init.d/S41igmpworkaround.platform_gfibertv
@@ -0,0 +1,23 @@
+#!/bin/sh
+. /etc/utils.sh
+
+case "$1" in
+  start)
+    if ! is-network-box && is-storage-box; then
+      # Avoid b/14248601 when talking to GFRG1x0 (or any other
+      # upstream IGMP snooping router, really).
+      sysctl -w net.ipv4.conf.all.force_igmp_version=2
+      babysit 60 multicast_join 239.0.0.1 | logos mcastjoin &
+    fi
+    ;;
+  stop)
+    pkillwait multicast_join
+    ;;
+  restart|reload)
+    "$0" stop
+    "$0" start
+    ;;
+  *)
+    echo "Usage: $0 {start|stop|restart}"
+    exit 1
+esac
diff --git a/fs/skeleton/etc/init.d/S42switch.platform_gfibertv b/fs/skeleton/etc/init.d/S42switch.platform_gfibertv
index 88a4b59..235cf3c 100755
--- a/fs/skeleton/etc/init.d/S42switch.platform_gfibertv
+++ b/fs/skeleton/etc/init.d/S42switch.platform_gfibertv
@@ -47,7 +47,7 @@
 
     if runnable ssdk_sh; then
       {
-        disable_multicast_flood_cmds
+        #disable_multicast_flood_cmds           # commented out for for b/16856861"
         disable_flowctrl_port0_cmds
         echo quit
       } | ssdk_sh 2>&1 | logos switch
@@ -56,7 +56,7 @@
   stop)
     if runnable ssdk_sh; then
       {
-        restore_defaults_cmd
+        #restore_defaults_cmds                  # commented out for for b/16856861"
         enable_flowctrl_port0_cmds
         echo quit
       } | ssdk_sh 2>&1 | logos switch
diff --git a/fs/skeleton/etc/init.d/S50wifi.platform_gfibertv b/fs/skeleton/etc/init.d/S50wifi.platform_gfibertv
index b60289d..20c136f 100755
--- a/fs/skeleton/etc/init.d/S50wifi.platform_gfibertv
+++ b/fs/skeleton/etc/init.d/S50wifi.platform_gfibertv
@@ -7,6 +7,13 @@
 
 case "$1" in
   start)
+    if is-network-box; then
+      babysit 60 waveguide --high-power --scan-interval=300 \
+          2>&1 | logos waveguide &
+    elif has_wifi; then
+      babysit 60 waveguide --no-high-power --scan-interval=300 \
+          2>&1 | logos waveguide &
+    fi
     if runnable wl && has_wifi && interface_exists eth2; then
       read wifimac </sys/class/net/eth2/address
       wl ap 1
@@ -17,6 +24,7 @@
     ;;
   stop)
     wifi stop
+    pkillwait -f waveguide
     ;;
   restart)
     $0 stop; $0 start
diff --git a/fs/skeleton/etc/init.d/S60harddisk.platform_gfibertv b/fs/skeleton/etc/init.d/S60harddisk.platform_gfibertv
index 24cc016..ada4d9c 100755
--- a/fs/skeleton/etc/init.d/S60harddisk.platform_gfibertv
+++ b/fs/skeleton/etc/init.d/S60harddisk.platform_gfibertv
@@ -60,6 +60,7 @@
       echo "Mounting ext4 /var/media from '$mediafs'"
       mount -o "$FLAGS" -t ext4 "$mediafs" /var/media
     elif [ -e /dev/sda ]; then
+      hdparm -q -B255 /dev/sda  # disable power saving
       check_pairing
       echo "Mounting SATA device."
       if [ -e /dev/sda1 ]; then
diff --git a/fs/skeleton/etc/utils.sh b/fs/skeleton/etc/utils.sh
index 2a4e8c3..6a8f678 100644
--- a/fs/skeleton/etc/utils.sh
+++ b/fs/skeleton/etc/utils.sh
@@ -18,8 +18,14 @@
 
 # Returns true if the system has wifi.
 has_wifi() {
-  WIFI_IF="eth2"
-  [ -f "/sys/class/net/$WIFI_IF/address" ] && runnable wl
+  for d in /sys/class/net/wlan*/address; do
+    [ -f "$d" ] && return 0
+  done
+  if runnable wl; then
+    # on boxes with wl, wifi is eth2
+    [ -f "/sys/class/net/eth2/address" ] && return 0
+  fi
+  return 1
 }
 
 
@@ -66,8 +72,10 @@
   # Start up native streaming server
   VIDEO_UID=$(id -u video)
   VIDEO_GID=$(id -g video)
-  babysit 10 alivemonitor /tmp/sagesrvalive 80 10 120 /app/sage/sagesrv -l6 -m5 \
-    -U $VIDEO_UID -G $VIDEO_GID -f 2>&1 | logos z 0 20000000 &
+  babysit 10 \
+  alivemonitor /tmp/sagesrvalive 80 10 120 \
+  /app/sage/sagesrv -l6 -m5 \
+      -U $VIDEO_UID -G $VIDEO_GID -f 2>&1 | logos z 0 20000000 &
 }
 
 stop_sagesrv() {
diff --git a/fs/skeleton/sbin/dhclient-script b/fs/skeleton/sbin/dhclient-script
index dbba586..0015de0 100755
--- a/fs/skeleton/sbin/dhclient-script
+++ b/fs/skeleton/sbin/dhclient-script
@@ -262,7 +262,7 @@
     rm -f /tmp/dnsmasq/ipv6.conf
     ip -6 addr flush dev $bridge_ifc scope global
     rm -f /tmp/dnsmasq/acs.conf
-    restart dnsmasq
+    QUIET=1 restart dnsmasq
   fi
 }
 
@@ -274,7 +274,8 @@
     BOUND|RENEW|REBIND|REBOOT)
       write_ntp_conf_new /tmp/ntpd4.servers
       if [ "$addr_added" = 1 ]; then
-        restart igmpproxy upnpd
+        QUIET=1 restart igmpproxy upnpd
+        runnable update-acs-iptables && update-acs-iptables
       fi
       ;;
 
@@ -293,7 +294,7 @@
       fi
 
       if [ "$restart_dnsmasq" != 0 ]; then
-        restart dnsmasq
+        QUIET=1 restart dnsmasq
       fi
 
       if runnable rdisc6 && \
diff --git a/fs/skeleton/sbin/factory_status.sh b/fs/skeleton/sbin/factory_status.sh
index 341a8e0..50c9f63 100755
--- a/fs/skeleton/sbin/factory_status.sh
+++ b/fs/skeleton/sbin/factory_status.sh
@@ -40,9 +40,11 @@
 
 echo
 
+do_print_certificate=0
 ssl="$(hnvram -rq GOOGLE_SSL_CRT 2>&1)"
 if [ "$?" -eq 0 ]; then
   echo GOOGLE_SSL_CRT is populated
+  do_print_certificate=1
 else
   echo GOOGLE_SSL_CRT is not populated
 fi
@@ -54,6 +56,11 @@
   echo GOOGLE_SSL_PEM is not populated
 fi
 
+if [ -n "$do_print_certificate" ]; then
+  echo "GOOGLE_SSL_CRT:"
+  echo "$(hnvram -rq GOOGLE_SSL_CRT 2>&1)"
+fi
+
 echo
 
 echo "$(hnvram -r MAC_ADDR 2>&1)"
diff --git a/fs/skeleton/sbin/hotplug b/fs/skeleton/sbin/hotplug
index 8f859f8..3c5a8c6 100755
--- a/fs/skeleton/sbin/hotplug
+++ b/fs/skeleton/sbin/hotplug
@@ -4,6 +4,14 @@
 HOTPLUG_FW_DIR=/lib/firmware
 exec >/dev/kmsg 2>&1
 
+# BlueZ: adjust repeat speed on remotes
+if [ "$SUBSYSTEM" = "input" -a "$ACTION" = "add" ]; then
+  if [ -n "$DEVNAME" -a -c "/dev/$DEVNAME" ]; then
+    echo "hotplug: setting autorepeat on $DEVNAME"
+    input-repeat -f /dev/$DEVNAME -d 600
+  fi
+fi
+
 # BlueZ: Configure hci0 interface link mode
 if [ "$SUBSYSTEM" = "bluetooth" -a "$ACTION" = "add" ]; then
   hcidev=${DEVPATH##*/}
diff --git a/fs/skeleton/usr/bin/input-repeat b/fs/skeleton/usr/bin/input-repeat
new file mode 100755
index 0000000..1d9f968
--- /dev/null
+++ b/fs/skeleton/usr/bin/input-repeat
@@ -0,0 +1,103 @@
+#!/usr/bin/python
+
+# Copyright 2014 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""almost a hundred lines to call 1 ioctl.  tool to tune remote repeat speed."""
+
+__author__ = "edjames@google.com (Ed James)"
+
+import fcntl
+import os
+import struct
+import sys
+import options
+
+optspec = """
+input-repeat -f /dev/input/eventX [-d delay] [-p period] [-m max (if supported)]
+--
+f,file=    Path to a /dev/input/event* device
+d,delay=   delay before repeat starts in milliseconds
+p,period=  time between repeats in milliseconds
+m,max=     maximum times to repeat (may not be available)
+"""
+
+
+def get_or_set_rep(efile, delay, period, maxrep):
+  """optionally apply changes and display settings."""
+  eviocgrep = 0x40084503
+  eviocsrep = 0x80084503
+
+  change = (delay is not None or period is not None or maxrep is not None)
+  efd = os.open(efile, os.O_RDWR)
+
+  vin = [0, 0, 0]
+  buf = struct.pack("@iii", *vin)
+  buf = fcntl.ioctl(efd, eviocgrep, buf)
+  vout = list(struct.unpack("@iii", buf))
+  if change:
+    vin = vout[:]
+    if delay is not None:
+      vin[0] = delay
+    if period:
+      vin[1] = period
+    if maxrep:
+      vin[2] = maxrep
+    buf = struct.pack("@iii", *vin)
+    fcntl.ioctl(efd, eviocsrep, buf)
+    vin = [0, 0, 0]
+    buf = struct.pack("@iii", *vin)
+    buf = fcntl.ioctl(efd, eviocgrep, buf)
+    vout = list(struct.unpack("@iii", buf))
+  print("{}: delay {} period {} max {} (0 means unsupported)".
+        format(efile, *vout))
+
+
+def main(argv):
+  """parse args and get or set hid repeat values."""
+  err = 0
+  delay = None
+  period = None
+  maxrep = None
+
+  opts = options.Options(optspec)
+  (opt, unused_flags, unused_extra) = opts.parse(argv[1:])
+  if unused_extra:
+    print "{}: extra arguments found".format(argv[0])
+    err += 1
+  if opt.file is None:
+    print "{}: -f/--file is required".format(argv[0])
+    err += 1
+
+  if opt.delay is not None:
+    delay = int(opt.delay)
+  if opt.period is not None:
+    period = int(opt.period)
+  if opt.max is not None:
+    maxrep = int(opt.max)
+
+  if ((delay is not None and delay < 1) or
+      (period is not None and period < 1) or
+      (maxrep is not None and maxrep < 1)):
+    print "{}: delay, period and/or max must be >= 1".format(argv[0])
+    err += 1
+
+  if err:
+    sys.exit(err)
+
+  get_or_set_rep(opt.file, delay, period, maxrep)
+
+
+if __name__ == "__main__":
+  main(sys.argv)
diff --git a/fs/skeleton/usr/bin/update-acs-iptables.platform_gfibertv b/fs/skeleton/usr/bin/update-acs-iptables.platform_gfibertv
index 5ad5110..4f4c5a1 100755
--- a/fs/skeleton/usr/bin/update-acs-iptables.platform_gfibertv
+++ b/fs/skeleton/usr/bin/update-acs-iptables.platform_gfibertv
@@ -46,6 +46,8 @@
 
 # ipv4 port mapping rules
 file=/tmp/cwmp_iptables
+min=0
+max=0
 if [ -f $file ]; then
   declare -A cwmp
   line=0
@@ -56,10 +58,17 @@
       continue
     fi
     cwmp[$key]="$value"
+    id=${key##CWMP_}
+    id=${id%%_*}
+    if [ "$id" -lt "$min" ] || [ "$min" = 0 ]; then
+      min="$id"
+    fi
+    if [ "$id" -gt "$max" ] || [ "$max" = 0 ]; then
+      max="$id"
+    fi
   done < $file
 
-  rule=1
-  while true; do
+  for rule in $(seq $min $max); do
     tag="CWMP_${rule}_"
 
     comment=${cwmp[${tag}COMMENT]}
@@ -71,15 +80,7 @@
     dport=${cwmp[${tag}DPORT]}
     enabled=${cwmp[${tag}ENABLE]}
 
-    rule=$(($rule + 1))
-
-    # 1 means proceed, 0 means skip, others mean abort
     if [ "$enabled" != 1 ]; then
-      if [ "$enabled" != 0 ]; then
-        # end of rules
-        break
-      fi
-      # not enabled
       continue
     fi
 
@@ -97,18 +98,21 @@
     iptables -t nat -A acsrules-nat-prerouting -i "$wans" -p "$protocol" -s "$source" -d "$gateway" --dport "$sport" \
       -j DNAT --to "$dest$dportnat" -m comment --comment "$comment"
     iptables -t nat -A acsrules-nat-postrouting -p "$protocol" -s "$lanipv4mask" -d "$dest" --dport "$dport" \
-      -j SNAT --to "$lanipv4"
-    iptables -A acsrules-filter-forward -p "$protocol" -d "$dest" --dport "$dport" -j ACCEPT
-    # this adds a lan rule so internal hosts can use the lan router ip to get the same mapping
+      -j SNAT --to "$lanipv4" -m comment --comment "$comment"
+    iptables -A acsrules-filter-forward -p "$protocol" -d "$dest" --dport "$dport" -j ACCEPT \
+      -m comment --comment "$comment"
+    # this adds a lan rule so internal hosts can use the wan router ip to get the same mapping
     if ( [ "$gateway" = "$wanipv4" ] || [ "$gateway" = 0/0 ] ) && [ "$source" = 0/0 ]; then
-      iptables -t nat -A acsrules-nat-prerouting -p "$protocol" -d "$lanipv4" --dport "$sport" \
-        -j DNAT --to "$dest$dportnat"
+      iptables -t nat -A acsrules-nat-prerouting -i br0 -p "$protocol" -d "$wanipv4" --dport "$sport" \
+        -j DNAT --to "$dest$dportnat" -m comment --comment "$comment"
     fi
   done
 fi
 
 # ipv6 port mapping rules
 file=/tmp/cwmp_ip6tables
+min=0
+max=0
 if [ -f $file ]; then
   declare -A cwmp6
   line=0
@@ -119,10 +123,17 @@
       continue
     fi
     cwmp6[$key]="$value"
+    id=${key##CWMP_}
+    id=${id%%_*}
+    if [ "$id" -lt "$min" ] || [ "$min" = 0 ]; then
+      min="$id"
+    fi
+    if [ "$id" -gt "$max" ] || [ "$max" = 0 ]; then
+      max="$id"
+    fi
   done < $file
 
-  rule=1
-  while true; do
+  for rule in $(seq $min $max); do
     tag="CWMP_${rule}_"
 
     comment=${cwmp6[${tag}COMMENT]}
@@ -133,14 +144,7 @@
     dport=${cwmp6[${tag}DPORT]}
     enabled=${cwmp6[${tag}ENABLE]}
 
-    rule=$(($rule + 1))
-    # 1 means proceed, 0 means skip, others mean abort
     if [ "$enabled" != 1 ]; then
-      if [ "$enabled" != 0 ]; then
-        # end of rules
-        break
-      fi
-      # not enabled
       continue
     fi
 
@@ -150,39 +154,58 @@
 
 # upnp IGD (firewall pinholes)
 # MINIUPNPD is maintained by miniupnpd
-if [ -f $acs/upnpd_enabled ]; then
+if [ -f /tmp/upnpd-enabled ]; then
   ip46tables -t filter -A acsrules-filter-forward -i $wans ! -o $wans -j MINIUPNPD
   iptables -t nat -A acsrules-nat-prerouting -d "$wanipv4" -i $wans -j MINIUPNPD
   ! /etc/init.d/S80upnpd isrunning && /etc/init.d/S80upnpd start
 else
-  /etc/init.d/S80upnpd isrunning && /etc/init.d/S80upnpd stop
+  QUIET=1 stop upnpd
 fi
 
 # ftp server
 if [ -f $acs/ftpserverv4 ]; then
   ftpserverv4=$(cat $acs/ftpserverv4)
-  iptables -t nat -A acsrules-nat-prerouting -p tcp ---dport 20 -j DNAT --to "$ftpserverv4":20
-  iptables -t nat -A acsrules-nat-prerouting -p tcp --dport 21 -j DNAT --to "$ftpserverv4":21
-  iptables -A acsrules-filter-forward -p tcp -d "$ftpserverv4" --dport 21 -m conntrack --ctstate NEW,ESTABLISHED ftp -j ACCEPT
-  iptables -A acsrules-filter-forward -p tcp -d "$ftpserverv4" --dport 20 -m conntrack --ctstate RELATED -m helper --helper ftp -j ACCEPT
-  iptables -A acsrules-filter-forward -p tcp -d "$ftpserverv4" --dport 1024: -m conntrack --ctstate RELATED -m helper --helper ftp -j ACCEPT
+  iptables -t nat -A acsrules-nat-prerouting -p tcp ---dport 20 -j DNAT \
+      --to "$ftpserverv4":20 -m comment --comment "ASF:FTP"
+  iptables -t nat -A acsrules-nat-prerouting -p tcp --dport 21 -j DNAT \
+      --to "$ftpserverv4":21 -m comment --comment "ASF:FTP"
+  iptables -A acsrules-filter-forward -p tcp -d "$ftpserverv4" --dport 21 \
+      -m conntrack --ctstate NEW,ESTABLISHED ftp \
+      -j ACCEPT -m comment --comment "ASF:FTP"
+  iptables -A acsrules-filter-forward -p tcp -d "$ftpserverv4" --dport 20 \
+      -m conntrack --ctstate RELATED -m helper --helper ftp -j ACCEPT \
+      -m comment --comment "ASF:FTP"
+  iptables -A acsrules-filter-forward -p tcp -d "$ftpserverv4" --dport 1024: \
+      -m conntrack --ctstate RELATED -m helper --helper ftp -j ACCEPT \
+      -m comment --comment "ASF:FTP"
 fi
 if [ -f $acs/ftpserverv6 ]; then
   ftpserverv6=$(cat $acs/ftpserverv6)
-  ip6tables -A acsrules-filter-forward -p tcp -d "$ftpserverv6" --dport 21 -m conntrack --ctstate NEW,ESTABLISHED ftp -j ACCEPT
-  ip6tables -A acsrules-filter-forward -p tcp -d "$ftpserverv6" --dport 20 -m conntrack --ctstate RELATED -m helper --helper ftp -j ACCEPT
-  ip6tables -A acsrules-filter-forward -p tcp -d "$ftpserverv6" --dport 1024: -m conntrack --ctstate RELATED -m helper --helper ftp -j ACCEPT
+  ip6tables -A acsrules-filter-forward -p tcp -d "$ftpserverv6" --dport 21 \
+      -m conntrack --ctstate NEW,ESTABLISHED ftp -j ACCEPT \
+      -m comment --comment "ASF:FTP6"
+  ip6tables -A acsrules-filter-forward -p tcp -d "$ftpserverv6" --dport 20 \
+      -m conntrack --ctstate RELATED -m helper --helper ftp -j ACCEPT \
+      -m comment --comment "ASF:FTP6"
+  ip6tables -A acsrules-filter-forward -p tcp -d "$ftpserverv6" --dport 1024: \
+      -m conntrack --ctstate RELATED -m helper --helper ftp -j ACCEPT \
+      -m comment --comment "ASF:FTP6"
 fi
 
 # DMZ, goes last
 if [ -f $acs/dmzhostv4 ]; then
   dmzhostv4=$(cat $acs/dmzhostv4)
-  iptables -t nat -A acsrules-nat-prerouting -i $wan -s 0/0 -d "$wanipv4" -j DNAT --to "$dmzhostv4"
-  iptables -A acsrules-filter-forward -i $wan -d "$dmzhostv4" -j ACCEPT
+  iptables -t nat -A acsrules-nat-prerouting -i $wan -s 0/0 -d "$wanipv4" \
+      -j DNAT --to "$dmzhostv4" -m comment --comment "DMZ4"
+  iptables -A acsrules-filter-forward -i $wan -d "$dmzhostv4" -j ACCEPT \
+      -m comment --comment "DMZ4"
 fi
 if [ -f $acs/dmzhostv6 ]; then
-  dmzhostv4=$(cat $acs/dmzhostv6)
-  iptables -A acsrules-filter-forward -i $wan -d "$dmzhostv6" -j ACCEPT
+  dmzhostv6=$(cat $acs/dmzhostv6)
+  iptables -A acsrules-filter-forward -i $wan -d "$dmzhostv6" -j ACCEPT \
+      -m comment --comment "DMZ6"
 fi
 
+(iptables-save; ip6tables-save) | logos iptables-save
+
 exit 0
diff --git a/package/Config.in b/package/Config.in
index 63ae922..e70e7c0 100644
--- a/package/Config.in
+++ b/package/Config.in
@@ -261,6 +261,8 @@
 source "package/python-mad/Config.in"
 source "package/python-netifaces/Config.in"
 source "package/python-pygame/Config.in"
+source "package/python-pyrex/Config.in.host"
+source "package/python-pypcap/Config.in"
 source "package/python-serial/Config.in"
 source "package/python-setuptools/Config.in"
 endmenu
diff --git a/package/backports-custom/backports-custom-0001-log-beacon-info.patch b/package/backports-custom/backports-custom-0001-log-beacon-info.patch
index decfc7c..b6a23a5 100644
--- a/package/backports-custom/backports-custom-0001-log-beacon-info.patch
+++ b/package/backports-custom/backports-custom-0001-log-beacon-info.patch
@@ -89,7 +89,7 @@
 +			ath10k_warn("beacon callback led to no beacon\n");
 +		} else if ((ath10k_debug_mask & ATH10K_DBG_BEACON) && beacon_count >= 50) {
 +			beacon_count = 0;
-+			ath10k_dbg(ATH10K_DBG_BEACON, "50 beacons sent");
++			ath10k_dbg(ATH10K_DBG_BEACON, "50 beacons sent\n");
 +		}
  	}
  }
diff --git a/package/backports-custom/backports-custom-0515-reset-harder.patch b/package/backports-custom/backports-custom-0515-reset-harder.patch
new file mode 100644
index 0000000..879e193
--- /dev/null
+++ b/package/backports-custom/backports-custom-0515-reset-harder.patch
@@ -0,0 +1,62 @@
+From 136ef8110cba61752eee5ef6bd7ce170b15cf491 Mon Sep 17 00:00:00 2001
+From: Michal Kazior <michal.kazior@tieto.com>
+Date: Wed, 14 May 2014 16:56:16 +0300
+Subject: [PATCH] ath10k: improve warm reset reliability
+
+Warm reset is now able to recover after device
+crashes which required a cold reset before.
+
+This should greatly reduce chances of getting data
+bus errors or host system freezes due to buggy
+cold reset on some chips.
+
+kvalo: use ath10k_pci_soc_*()
+
+Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
+Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
+---
+ drivers/net/wireless/ath/ath10k/pci.c | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
+index 66b1f30..02dc408 100644
+--- a/drivers/net/wireless/ath/ath10k/pci.c
++++ b/drivers/net/wireless/ath/ath10k/pci.c
+@@ -1802,6 +1802,26 @@ static void ath10k_pci_fw_interrupt_handler(struct ath10k *ar)
+ 	ath10k_pci_sleep(ar);
+ }
+ 
++/* this function effectively clears target memory controller assert line */
++static void ath10k_pci_warm_reset_si0(struct ath10k *ar)
++{
++	u32 val;
++
++	val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS);
++	ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS,
++			       val | SOC_RESET_CONTROL_SI0_RST_MASK);
++	val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS);
++
++	msleep(10);
++
++	val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS);
++	ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS,
++			       val & ~SOC_RESET_CONTROL_SI0_RST_MASK);
++	val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS);
++
++	msleep(10);
++}
++
+ static int ath10k_pci_warm_reset(struct ath10k *ar)
+ {
+ 	int ret = 0;
+@@ -1860,6 +1880,8 @@ static int ath10k_pci_warm_reset(struct ath10k *ar)
+ 				SOC_RESET_CONTROL_ADDRESS);
+ 	msleep(10);
+ 
++	ath10k_pci_warm_reset_si0(ar);
++
+ 	/* debug */
+ 	val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS +
+ 				PCIE_INTR_CAUSE_ADDRESS);
+-- 
+2.0.4
diff --git a/package/backports-custom/backports-custom-0516-retry-reset.patch b/package/backports-custom/backports-custom-0516-retry-reset.patch
new file mode 100644
index 0000000..7895db9
--- /dev/null
+++ b/package/backports-custom/backports-custom-0516-retry-reset.patch
@@ -0,0 +1,70 @@
+Sometimes warm reset works upon retry. It might be
+related to imperfect warm reset routine, but for
+now let's just do the retries.
+
+This should improve the reliability of some chips
+that hang/crash with cold reset which is used as a
+last resort if warm reset fails.
+
+Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
+---
+ drivers/net/wireless/ath/ath10k/pci.c | 29 ++++++++++++++++++++++++++---
+ 1 file changed, 26 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
+index c9b14b4..c9e482e 100644
+--- a/drivers/net/wireless/ath/ath10k/pci.c
++++ b/drivers/net/wireless/ath/ath10k/pci.c
+@@ -59,6 +59,7 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)");
+ 
+ /* how long wait to wait for target to initialise, in ms */
+ #define ATH10K_PCI_TARGET_WAIT 3000
++#define ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS 3
+ 
+ #define QCA988X_2_0_DEVICE_ID	(0x003c)
+ 
+@@ -2012,6 +2013,28 @@ err:
+ 	return ret;
+ }
+ 
++static int ath10k_pci_hif_power_up_warm(struct ath10k *ar)
++{
++	int i, ret;
++
++	/*
++	 * Sometime warm reset succeeds after retries.
++	 *
++	 * FIXME: It might be possible to tune ath10k_pci_warm_reset() to work
++	 * at first try.
++	 */
++	for (i = 0; i < ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS; i++) {
++		ret = __ath10k_pci_hif_power_up(ar, false);
++		if (ret == 0)
++			break;
++
++		ath10k_warn("failed to warm reset (attempt %d out of %d): %d\n",
++			    i + 1, ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS, ret);
++	}
++
++	return ret;
++}
++
+ static int ath10k_pci_hif_power_up(struct ath10k *ar)
+ {
+ 	int ret;
+@@ -2023,10 +2046,10 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
+ 	 * preferred (and safer) way to perform a device reset is through a
+ 	 * warm reset.
+ 	 *
+-	 * Warm reset doesn't always work though (notably after a firmware
+-	 * crash) so fall back to cold reset if necessary.
++	 * Warm reset doesn't always work though so fall back to cold reset may
++	 * be necessary.
+ 	 */
+-	ret = __ath10k_pci_hif_power_up(ar, false);
++	ret = ath10k_pci_hif_power_up_warm(ar);
+ 	if (ret) {
+ 		ath10k_warn("failed to power up target using warm reset: %d\n",
+ 			    ret);
+-- 
+1.8.5.3
diff --git a/package/backports-custom/backports-custom-0530-firmware-10-2-support.patch b/package/backports-custom/backports-custom-0530-firmware-10-2-support.patch
new file mode 100644
index 0000000..65ff06f
--- /dev/null
+++ b/package/backports-custom/backports-custom-0530-firmware-10-2-support.patch
@@ -0,0 +1,943 @@
+From 24c88f7807fb7c723690474d0a5d3441468185d9 Mon Sep 17 00:00:00 2001
+From: Michal Kazior <michal.kazior@tieto.com>
+Date: Fri, 25 Jul 2014 13:32:17 +0200
+Subject: [PATCH] ath10k: add support for 10.2 firmware
+
+The 10.2 firmware is a successor of 10.1 firmware
+(formerly identified as 10.x). Both share a lot
+but have some slight ABI differences that need to
+be taken care of.
+
+The 10.2 firmware introduces some new features but
+those can be added in subsequent patches. This
+patch makes ath10k boot and work with 10.2 with
+comparable functionality to 10.1.
+
+Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
+Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
+---
+ drivers/net/wireless/ath/ath10k/core.c |  14 +
+ drivers/net/wireless/ath/ath10k/core.h |   5 +
+ drivers/net/wireless/ath/ath10k/hw.h   |   3 +-
+ drivers/net/wireless/ath/ath10k/pci.c  |   2 +-
+ drivers/net/wireless/ath/ath10k/wmi.c  | 451 +++++++++++++++++++++++++++++++--
+ drivers/net/wireless/ath/ath10k/wmi.h  | 233 ++++++++++++++++-
+ 6 files changed, 678 insertions(+), 30 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
+index 93adb8c..bef797d 100644
+--- a/drivers/net/wireless/ath/ath10k/core.c
++++ b/drivers/net/wireless/ath/ath10k/core.c
+@@ -499,6 +499,13 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
+ 		goto err;
+ 	}
+ 
++	if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features) &&
++	    !test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
++		ath10k_err("feature bits corrupted: 10.2 feature requires 10.x feature to be set as well");
++		ret = -EINVAL;
++		goto err;
++	}
++
+ 	/* now fetch the board file */
+ 	if (ar->hw_params.fw.board == NULL) {
+ 		ath10k_err("board data file not defined");
+@@ -531,6 +538,13 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
+ {
+ 	int ret;
+ 
++	ar->fw_api = 3;
++	ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
++
++	ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API3_FILE);
++	if (ret == 0)
++		goto success;
++
+ 	ar->fw_api = 2;
+ 	ath10k_dbg(ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+ 
+diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
+index 83a5fa9..ded3af2 100644
+--- a/drivers/net/wireless/ath/ath10k/core.h
++++ b/drivers/net/wireless/ath/ath10k/core.h
+@@ -330,6 +330,11 @@ enum ath10k_fw_features {
+ 	/* Firmware does not support P2P */
+ 	ATH10K_FW_FEATURE_NO_P2P = 3,
+ 
++	/* Firmware 10.2 feature bit. The ATH10K_FW_FEATURE_WMI_10X feature bit
++	 * is required to be set as well.
++	 */
++	ATH10K_FW_FEATURE_WMI_10_2 = 4,
++
+ 	/* keep last */
+ 	ATH10K_FW_FEATURE_COUNT,
+ };
+diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
+index 007e855..ffd0489 100644
+--- a/drivers/net/wireless/ath/ath10k/hw.h
++++ b/drivers/net/wireless/ath/ath10k/hw.h
+@@ -28,12 +28,13 @@
+ #define QCA988X_HW_2_0_CHIP_ID_REV	0x2
+ #define QCA988X_HW_2_0_FW_DIR		"ath10k/QCA988X/hw2.0"
+ #define QCA988X_HW_2_0_FW_FILE		"firmware.bin"
+-#define QCA988X_HW_2_0_FW_2_FILE	"firmware-2.bin"
++#define QCA988X_HW_2_0_FW_3_FILE	"firmware-3.bin"
+ #define QCA988X_HW_2_0_OTP_FILE		"otp.bin"
+ #define QCA988X_HW_2_0_BOARD_DATA_FILE	"board.bin"
+ #define QCA988X_HW_2_0_PATCH_LOAD_ADDR	0x1234
+ 
+ #define ATH10K_FW_API2_FILE		"firmware-2.bin"
++#define ATH10K_FW_API3_FILE		"firmware-3.bin"
+ 
+ /* includes also the null byte */
+ #define ATH10K_FIRMWARE_MAGIC               "QCA-ATH10K"
+diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
+index 0ffff20..2d340cc 100644
+--- a/drivers/net/wireless/ath/ath10k/pci.c
++++ b/drivers/net/wireless/ath/ath10k/pci.c
+@@ -2809,5 +2809,5 @@ module_exit(ath10k_pci_exit);
+ MODULE_AUTHOR("Qualcomm Atheros");
+ MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices");
+ MODULE_LICENSE("Dual BSD/GPL");
+-MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_2_FILE);
++MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_3_FILE);
+ MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE);
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index c2c87c9..b09661d 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -487,6 +487,127 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = {
+ 	.burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE,
+ };
+ 
++/* firmware 10.2 specific mappings */
++static struct wmi_cmd_map wmi_10_2_cmd_map = {
++	.init_cmdid = WMI_10_2_INIT_CMDID,
++	.start_scan_cmdid = WMI_10_2_START_SCAN_CMDID,
++	.stop_scan_cmdid = WMI_10_2_STOP_SCAN_CMDID,
++	.scan_chan_list_cmdid = WMI_10_2_SCAN_CHAN_LIST_CMDID,
++	.scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED,
++	.pdev_set_regdomain_cmdid = WMI_10_2_PDEV_SET_REGDOMAIN_CMDID,
++	.pdev_set_channel_cmdid = WMI_10_2_PDEV_SET_CHANNEL_CMDID,
++	.pdev_set_param_cmdid = WMI_10_2_PDEV_SET_PARAM_CMDID,
++	.pdev_pktlog_enable_cmdid = WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID,
++	.pdev_pktlog_disable_cmdid = WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID,
++	.pdev_set_wmm_params_cmdid = WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID,
++	.pdev_set_ht_cap_ie_cmdid = WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID,
++	.pdev_set_vht_cap_ie_cmdid = WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID,
++	.pdev_set_quiet_mode_cmdid = WMI_10_2_PDEV_SET_QUIET_MODE_CMDID,
++	.pdev_green_ap_ps_enable_cmdid = WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID,
++	.pdev_get_tpc_config_cmdid = WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID,
++	.pdev_set_base_macaddr_cmdid = WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID,
++	.vdev_create_cmdid = WMI_10_2_VDEV_CREATE_CMDID,
++	.vdev_delete_cmdid = WMI_10_2_VDEV_DELETE_CMDID,
++	.vdev_start_request_cmdid = WMI_10_2_VDEV_START_REQUEST_CMDID,
++	.vdev_restart_request_cmdid = WMI_10_2_VDEV_RESTART_REQUEST_CMDID,
++	.vdev_up_cmdid = WMI_10_2_VDEV_UP_CMDID,
++	.vdev_stop_cmdid = WMI_10_2_VDEV_STOP_CMDID,
++	.vdev_down_cmdid = WMI_10_2_VDEV_DOWN_CMDID,
++	.vdev_set_param_cmdid = WMI_10_2_VDEV_SET_PARAM_CMDID,
++	.vdev_install_key_cmdid = WMI_10_2_VDEV_INSTALL_KEY_CMDID,
++	.peer_create_cmdid = WMI_10_2_PEER_CREATE_CMDID,
++	.peer_delete_cmdid = WMI_10_2_PEER_DELETE_CMDID,
++	.peer_flush_tids_cmdid = WMI_10_2_PEER_FLUSH_TIDS_CMDID,
++	.peer_set_param_cmdid = WMI_10_2_PEER_SET_PARAM_CMDID,
++	.peer_assoc_cmdid = WMI_10_2_PEER_ASSOC_CMDID,
++	.peer_add_wds_entry_cmdid = WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID,
++	.peer_remove_wds_entry_cmdid = WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID,
++	.peer_mcast_group_cmdid = WMI_10_2_PEER_MCAST_GROUP_CMDID,
++	.bcn_tx_cmdid = WMI_10_2_BCN_TX_CMDID,
++	.pdev_send_bcn_cmdid = WMI_10_2_PDEV_SEND_BCN_CMDID,
++	.bcn_tmpl_cmdid = WMI_CMD_UNSUPPORTED,
++	.bcn_filter_rx_cmdid = WMI_10_2_BCN_FILTER_RX_CMDID,
++	.prb_req_filter_rx_cmdid = WMI_10_2_PRB_REQ_FILTER_RX_CMDID,
++	.mgmt_tx_cmdid = WMI_10_2_MGMT_TX_CMDID,
++	.prb_tmpl_cmdid = WMI_CMD_UNSUPPORTED,
++	.addba_clear_resp_cmdid = WMI_10_2_ADDBA_CLEAR_RESP_CMDID,
++	.addba_send_cmdid = WMI_10_2_ADDBA_SEND_CMDID,
++	.addba_status_cmdid = WMI_10_2_ADDBA_STATUS_CMDID,
++	.delba_send_cmdid = WMI_10_2_DELBA_SEND_CMDID,
++	.addba_set_resp_cmdid = WMI_10_2_ADDBA_SET_RESP_CMDID,
++	.send_singleamsdu_cmdid = WMI_10_2_SEND_SINGLEAMSDU_CMDID,
++	.sta_powersave_mode_cmdid = WMI_10_2_STA_POWERSAVE_MODE_CMDID,
++	.sta_powersave_param_cmdid = WMI_10_2_STA_POWERSAVE_PARAM_CMDID,
++	.sta_mimo_ps_mode_cmdid = WMI_10_2_STA_MIMO_PS_MODE_CMDID,
++	.pdev_dfs_enable_cmdid = WMI_10_2_PDEV_DFS_ENABLE_CMDID,
++	.pdev_dfs_disable_cmdid = WMI_10_2_PDEV_DFS_DISABLE_CMDID,
++	.roam_scan_mode = WMI_10_2_ROAM_SCAN_MODE,
++	.roam_scan_rssi_threshold = WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD,
++	.roam_scan_period = WMI_10_2_ROAM_SCAN_PERIOD,
++	.roam_scan_rssi_change_threshold =
++				WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
++	.roam_ap_profile = WMI_10_2_ROAM_AP_PROFILE,
++	.ofl_scan_add_ap_profile = WMI_10_2_OFL_SCAN_ADD_AP_PROFILE,
++	.ofl_scan_remove_ap_profile = WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE,
++	.ofl_scan_period = WMI_10_2_OFL_SCAN_PERIOD,
++	.p2p_dev_set_device_info = WMI_10_2_P2P_DEV_SET_DEVICE_INFO,
++	.p2p_dev_set_discoverability = WMI_10_2_P2P_DEV_SET_DISCOVERABILITY,
++	.p2p_go_set_beacon_ie = WMI_10_2_P2P_GO_SET_BEACON_IE,
++	.p2p_go_set_probe_resp_ie = WMI_10_2_P2P_GO_SET_PROBE_RESP_IE,
++	.p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED,
++	.ap_ps_peer_param_cmdid = WMI_10_2_AP_PS_PEER_PARAM_CMDID,
++	.ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED,
++	.peer_rate_retry_sched_cmdid = WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID,
++	.wlan_profile_trigger_cmdid = WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID,
++	.wlan_profile_set_hist_intvl_cmdid =
++				WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
++	.wlan_profile_get_profile_data_cmdid =
++				WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
++	.wlan_profile_enable_profile_id_cmdid =
++				WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
++	.wlan_profile_list_profile_id_cmdid =
++				WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
++	.pdev_suspend_cmdid = WMI_10_2_PDEV_SUSPEND_CMDID,
++	.pdev_resume_cmdid = WMI_10_2_PDEV_RESUME_CMDID,
++	.add_bcn_filter_cmdid = WMI_10_2_ADD_BCN_FILTER_CMDID,
++	.rmv_bcn_filter_cmdid = WMI_10_2_RMV_BCN_FILTER_CMDID,
++	.wow_add_wake_pattern_cmdid = WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID,
++	.wow_del_wake_pattern_cmdid = WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID,
++	.wow_enable_disable_wake_event_cmdid =
++				WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
++	.wow_enable_cmdid = WMI_10_2_WOW_ENABLE_CMDID,
++	.wow_hostwakeup_from_sleep_cmdid =
++				WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
++	.rtt_measreq_cmdid = WMI_10_2_RTT_MEASREQ_CMDID,
++	.rtt_tsf_cmdid = WMI_10_2_RTT_TSF_CMDID,
++	.vdev_spectral_scan_configure_cmdid =
++				WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID,
++	.vdev_spectral_scan_enable_cmdid =
++				WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID,
++	.request_stats_cmdid = WMI_10_2_REQUEST_STATS_CMDID,
++	.set_arp_ns_offload_cmdid = WMI_CMD_UNSUPPORTED,
++	.network_list_offload_config_cmdid = WMI_CMD_UNSUPPORTED,
++	.gtk_offload_cmdid = WMI_CMD_UNSUPPORTED,
++	.csa_offload_enable_cmdid = WMI_CMD_UNSUPPORTED,
++	.csa_offload_chanswitch_cmdid = WMI_CMD_UNSUPPORTED,
++	.chatter_set_mode_cmdid = WMI_CMD_UNSUPPORTED,
++	.peer_tid_addba_cmdid = WMI_CMD_UNSUPPORTED,
++	.peer_tid_delba_cmdid = WMI_CMD_UNSUPPORTED,
++	.sta_dtim_ps_method_cmdid = WMI_CMD_UNSUPPORTED,
++	.sta_uapsd_auto_trig_cmdid = WMI_CMD_UNSUPPORTED,
++	.sta_keepalive_cmd = WMI_CMD_UNSUPPORTED,
++	.echo_cmdid = WMI_10_2_ECHO_CMDID,
++	.pdev_utf_cmdid = WMI_10_2_PDEV_UTF_CMDID,
++	.dbglog_cfg_cmdid = WMI_10_2_DBGLOG_CFG_CMDID,
++	.pdev_qvit_cmdid = WMI_10_2_PDEV_QVIT_CMDID,
++	.pdev_ftm_intg_cmdid = WMI_CMD_UNSUPPORTED,
++	.vdev_set_keepalive_cmdid = WMI_CMD_UNSUPPORTED,
++	.vdev_get_keepalive_cmdid = WMI_CMD_UNSUPPORTED,
++	.force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED,
++	.gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID,
++	.gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID,
++};
++
+ int ath10k_wmi_wait_for_service_ready(struct ath10k *ar)
+ {
+ 	int ret;
+@@ -2325,20 +2446,144 @@ static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb)
+ 	dev_kfree_skb(skb);
+ }
+ 
++static void ath10k_wmi_10_2_process_rx(struct ath10k *ar, struct sk_buff *skb)
++{
++	struct wmi_cmd_hdr *cmd_hdr;
++	enum wmi_10_2_event_id id;
++
++	cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
++	id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
++
++	if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
++		return;
++
++	trace_ath10k_wmi_event(id, skb->data, skb->len);
++
++	switch (id) {
++	case WMI_10_2_MGMT_RX_EVENTID:
++		ath10k_wmi_event_mgmt_rx(ar, skb);
++		/* mgmt_rx() owns the skb now! */
++		return;
++	case WMI_10_2_SCAN_EVENTID:
++		ath10k_wmi_event_scan(ar, skb);
++		break;
++	case WMI_10_2_CHAN_INFO_EVENTID:
++		ath10k_wmi_event_chan_info(ar, skb);
++		break;
++	case WMI_10_2_ECHO_EVENTID:
++		ath10k_wmi_event_echo(ar, skb);
++		break;
++	case WMI_10_2_DEBUG_MESG_EVENTID:
++		ath10k_wmi_event_debug_mesg(ar, skb);
++		break;
++	case WMI_10_2_UPDATE_STATS_EVENTID:
++		ath10k_wmi_event_update_stats(ar, skb);
++		break;
++	case WMI_10_2_VDEV_START_RESP_EVENTID:
++		ath10k_wmi_event_vdev_start_resp(ar, skb);
++		break;
++	case WMI_10_2_VDEV_STOPPED_EVENTID:
++		ath10k_wmi_event_vdev_stopped(ar, skb);
++		break;
++	case WMI_10_2_PEER_STA_KICKOUT_EVENTID:
++		ath10k_wmi_event_peer_sta_kickout(ar, skb);
++		break;
++	case WMI_10_2_HOST_SWBA_EVENTID:
++		ath10k_wmi_event_host_swba(ar, skb);
++		break;
++	case WMI_10_2_TBTTOFFSET_UPDATE_EVENTID:
++		ath10k_wmi_event_tbttoffset_update(ar, skb);
++		break;
++	case WMI_10_2_PHYERR_EVENTID:
++		ath10k_wmi_event_phyerr(ar, skb);
++		break;
++	case WMI_10_2_ROAM_EVENTID:
++		ath10k_wmi_event_roam(ar, skb);
++		break;
++	case WMI_10_2_PROFILE_MATCH:
++		ath10k_wmi_event_profile_match(ar, skb);
++		break;
++	case WMI_10_2_DEBUG_PRINT_EVENTID:
++		ath10k_wmi_event_debug_print(ar, skb);
++		break;
++	case WMI_10_2_PDEV_QVIT_EVENTID:
++		ath10k_wmi_event_pdev_qvit(ar, skb);
++		break;
++	case WMI_10_2_WLAN_PROFILE_DATA_EVENTID:
++		ath10k_wmi_event_wlan_profile_data(ar, skb);
++		break;
++	case WMI_10_2_RTT_MEASUREMENT_REPORT_EVENTID:
++		ath10k_wmi_event_rtt_measurement_report(ar, skb);
++		break;
++	case WMI_10_2_TSF_MEASUREMENT_REPORT_EVENTID:
++		ath10k_wmi_event_tsf_measurement_report(ar, skb);
++		break;
++	case WMI_10_2_RTT_ERROR_REPORT_EVENTID:
++		ath10k_wmi_event_rtt_error_report(ar, skb);
++		break;
++	case WMI_10_2_WOW_WAKEUP_HOST_EVENTID:
++		ath10k_wmi_event_wow_wakeup_host(ar, skb);
++		break;
++	case WMI_10_2_DCS_INTERFERENCE_EVENTID:
++		ath10k_wmi_event_dcs_interference(ar, skb);
++		break;
++	case WMI_10_2_PDEV_TPC_CONFIG_EVENTID:
++		ath10k_wmi_event_pdev_tpc_config(ar, skb);
++		break;
++	case WMI_10_2_INST_RSSI_STATS_EVENTID:
++		ath10k_wmi_event_inst_rssi_stats(ar, skb);
++		break;
++	case WMI_10_2_VDEV_STANDBY_REQ_EVENTID:
++		ath10k_wmi_event_vdev_standby_req(ar, skb);
++		break;
++	case WMI_10_2_VDEV_RESUME_REQ_EVENTID:
++		ath10k_wmi_event_vdev_resume_req(ar, skb);
++		break;
++	case WMI_10_2_SERVICE_READY_EVENTID:
++		ath10k_wmi_10x_service_ready_event_rx(ar, skb);
++		break;
++	case WMI_10_2_READY_EVENTID:
++		ath10k_wmi_ready_event_rx(ar, skb);
++		break;
++	case WMI_10_2_RTT_KEEPALIVE_EVENTID:
++	case WMI_10_2_GPIO_INPUT_EVENTID:
++	case WMI_10_2_PEER_RATECODE_LIST_EVENTID:
++	case WMI_10_2_GENERIC_BUFFER_EVENTID:
++	case WMI_10_2_MCAST_BUF_RELEASE_EVENTID:
++	case WMI_10_2_MCAST_LIST_AGEOUT_EVENTID:
++	case WMI_10_2_WDS_PEER_EVENTID:
++		ath10k_dbg(ATH10K_DBG_WMI,
++			   "received event id %d not implemented\n", id);
++		break;
++	default:
++		ath10k_warn("Unknown eventid: %d\n", id);
++		break;
++	}
++
++	dev_kfree_skb(skb);
++}
+ 
+ static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb)
+ {
+-	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
+-		ath10k_wmi_10x_process_rx(ar, skb);
+-	else
++	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
++		if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
++			ath10k_wmi_10_2_process_rx(ar, skb);
++		else
++			ath10k_wmi_10x_process_rx(ar, skb);
++	} else {
+ 		ath10k_wmi_main_process_rx(ar, skb);
++	}
+ }
+ 
+ /* WMI Initialization functions */
+ int ath10k_wmi_attach(struct ath10k *ar)
+ {
+ 	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+-		ar->wmi.cmd = &wmi_10x_cmd_map;
++		if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
++			ar->wmi.cmd = &wmi_10_2_cmd_map;
++		else
++			ar->wmi.cmd = &wmi_10x_cmd_map;
++
+ 		ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
+ 		ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
+ 	} else {
+@@ -2738,14 +2983,109 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
+ 	return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
+ }
+ 
++static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar)
++{
++	struct wmi_init_cmd_10_2 *cmd;
++	struct sk_buff *buf;
++	struct wmi_resource_config_10x config = {};
++	u32 len, val;
++	int i;
++
++	config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
++	config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
++	config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS);
++	config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS);
++	config.ast_skid_limit = __cpu_to_le32(TARGET_10X_AST_SKID_LIMIT);
++	config.tx_chain_mask = __cpu_to_le32(TARGET_10X_TX_CHAIN_MASK);
++	config.rx_chain_mask = __cpu_to_le32(TARGET_10X_RX_CHAIN_MASK);
++	config.rx_timeout_pri_vo = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
++	config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
++	config.rx_timeout_pri_be = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
++	config.rx_timeout_pri_bk = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_HI_PRI);
++	config.rx_decap_mode = __cpu_to_le32(TARGET_10X_RX_DECAP_MODE);
++
++	config.scan_max_pending_reqs =
++		__cpu_to_le32(TARGET_10X_SCAN_MAX_PENDING_REQS);
++
++	config.bmiss_offload_max_vdev =
++		__cpu_to_le32(TARGET_10X_BMISS_OFFLOAD_MAX_VDEV);
++
++	config.roam_offload_max_vdev =
++		__cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_VDEV);
++
++	config.roam_offload_max_ap_profiles =
++		__cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_AP_PROFILES);
++
++	config.num_mcast_groups = __cpu_to_le32(TARGET_10X_NUM_MCAST_GROUPS);
++	config.num_mcast_table_elems =
++		__cpu_to_le32(TARGET_10X_NUM_MCAST_TABLE_ELEMS);
++
++	config.mcast2ucast_mode = __cpu_to_le32(TARGET_10X_MCAST2UCAST_MODE);
++	config.tx_dbg_log_size = __cpu_to_le32(TARGET_10X_TX_DBG_LOG_SIZE);
++	config.num_wds_entries = __cpu_to_le32(TARGET_10X_NUM_WDS_ENTRIES);
++	config.dma_burst_size = __cpu_to_le32(TARGET_10X_DMA_BURST_SIZE);
++	config.mac_aggr_delim = __cpu_to_le32(TARGET_10X_MAC_AGGR_DELIM);
++
++	val = TARGET_10X_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK;
++	config.rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(val);
++
++	config.vow_config = __cpu_to_le32(TARGET_10X_VOW_CONFIG);
++
++	config.num_msdu_desc = __cpu_to_le32(TARGET_10X_NUM_MSDU_DESC);
++	config.max_frag_entries = __cpu_to_le32(TARGET_10X_MAX_FRAG_ENTRIES);
++
++	len = sizeof(*cmd) +
++	      (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks);
++
++	buf = ath10k_wmi_alloc_skb(len);
++	if (!buf)
++		return -ENOMEM;
++
++	cmd = (struct wmi_init_cmd_10_2 *)buf->data;
++
++	if (ar->wmi.num_mem_chunks == 0) {
++		cmd->num_host_mem_chunks = 0;
++		goto out;
++	}
++
++	ath10k_dbg(ATH10K_DBG_WMI, "wmi sending %d memory chunks info.\n",
++		   ar->wmi.num_mem_chunks);
++
++	cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
++
++	for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
++		cmd->host_mem_chunks[i].ptr =
++			__cpu_to_le32(ar->wmi.mem_chunks[i].paddr);
++		cmd->host_mem_chunks[i].size =
++			__cpu_to_le32(ar->wmi.mem_chunks[i].len);
++		cmd->host_mem_chunks[i].req_id =
++			__cpu_to_le32(ar->wmi.mem_chunks[i].req_id);
++
++		ath10k_dbg(ATH10K_DBG_WMI,
++			   "wmi chunk %d len %d requested, addr 0x%llx\n",
++			   i,
++			   ar->wmi.mem_chunks[i].len,
++			   (unsigned long long)ar->wmi.mem_chunks[i].paddr);
++	}
++out:
++	memcpy(&cmd->resource_config.common, &config, sizeof(config));
++
++	ath10k_dbg(ATH10K_DBG_WMI, "wmi init 10.2\n");
++	return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
++}
++
+ int ath10k_wmi_cmd_init(struct ath10k *ar)
+ {
+ 	int ret;
+ 
+-	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
+-		ret = ath10k_wmi_10x_cmd_init(ar);
+-	else
++	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
++		if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
++			ret = ath10k_wmi_10_2_cmd_init(ar);
++		else
++			ret = ath10k_wmi_10x_cmd_init(ar);
++	} else {
+ 		ret = ath10k_wmi_main_cmd_init(ar);
++	}
+ 
+ 	return ret;
+ }
+@@ -2865,8 +3205,8 @@ int ath10k_wmi_start_scan(struct ath10k *ar,
+ 		channels->num_chan = __cpu_to_le32(arg->n_channels);
+ 
+ 		for (i = 0; i < arg->n_channels; i++)
+-			channels->channel_list[i] =
+-				__cpu_to_le32(arg->channels[i]);
++			channels->channel_list[i].freq =
++				__cpu_to_le16(arg->channels[i]);
+ 
+ 		off += sizeof(*channels);
+ 		off += sizeof(__le32) * arg->n_channels;
+@@ -3447,24 +3787,12 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar,
+ 	return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid);
+ }
+ 
+-int ath10k_wmi_peer_assoc(struct ath10k *ar,
+-			  const struct wmi_peer_assoc_complete_arg *arg)
++static void
++ath10k_wmi_peer_assoc_fill(struct ath10k *ar, void *buf,
++			   const struct wmi_peer_assoc_complete_arg *arg)
+ {
+-	struct wmi_peer_assoc_complete_cmd *cmd;
+-	struct sk_buff *skb;
++	struct wmi_common_peer_assoc_complete_cmd *cmd = buf;
+ 
+-	if (arg->peer_mpdu_density > 16)
+-		return -EINVAL;
+-	if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES)
+-		return -EINVAL;
+-	if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES)
+-		return -EINVAL;
+-
+-	skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
+-	if (!skb)
+-		return -ENOMEM;
+-
+-	cmd = (struct wmi_peer_assoc_complete_cmd *)skb->data;
+ 	cmd->vdev_id            = __cpu_to_le32(arg->vdev_id);
+ 	cmd->peer_new_assoc     = __cpu_to_le32(arg->peer_reassoc ? 0 : 1);
+ 	cmd->peer_associd       = __cpu_to_le32(arg->peer_aid);
+@@ -3499,6 +3827,78 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar,
+ 		__cpu_to_le32(arg->peer_vht_rates.tx_max_rate);
+ 	cmd->peer_vht_rates.tx_mcs_set =
+ 		__cpu_to_le32(arg->peer_vht_rates.tx_mcs_set);
++}
++
++static void
++ath10k_wmi_peer_assoc_fill_main(struct ath10k *ar, void *buf,
++				const struct wmi_peer_assoc_complete_arg *arg)
++{
++	struct wmi_main_peer_assoc_complete_cmd *cmd = buf;
++
++	ath10k_wmi_peer_assoc_fill(ar, buf, arg);
++	memset(cmd->peer_ht_info, 0, sizeof(cmd->peer_ht_info));
++}
++
++static void
++ath10k_wmi_peer_assoc_fill_10_1(struct ath10k *ar, void *buf,
++				const struct wmi_peer_assoc_complete_arg *arg)
++{
++	ath10k_wmi_peer_assoc_fill(ar, buf, arg);
++}
++
++static void
++ath10k_wmi_peer_assoc_fill_10_2(struct ath10k *ar, void *buf,
++				const struct wmi_peer_assoc_complete_arg *arg)
++{
++	struct wmi_10_2_peer_assoc_complete_cmd *cmd = buf;
++	int max_mcs, max_nss;
++	u32 info0;
++
++	/* TODO: Is using max values okay with firmware? */
++	max_mcs = 0xf;
++	max_nss = 0xf;
++
++	info0 = SM(max_mcs, WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX) |
++		SM(max_nss, WMI_PEER_ASSOC_INFO0_MAX_NSS);
++
++	ath10k_wmi_peer_assoc_fill(ar, buf, arg);
++	cmd->info0 = __cpu_to_le32(info0);
++}
++
++int ath10k_wmi_peer_assoc(struct ath10k *ar,
++			  const struct wmi_peer_assoc_complete_arg *arg)
++{
++	struct sk_buff *skb;
++	int len;
++
++	if (arg->peer_mpdu_density > 16)
++		return -EINVAL;
++	if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES)
++		return -EINVAL;
++	if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES)
++		return -EINVAL;
++
++	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
++		if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
++			len = sizeof(struct wmi_10_2_peer_assoc_complete_cmd);
++		else
++			len = sizeof(struct wmi_10_1_peer_assoc_complete_cmd);
++	} else {
++		len = sizeof(struct wmi_main_peer_assoc_complete_cmd);
++	}
++
++	skb = ath10k_wmi_alloc_skb(len);
++	if (!skb)
++		return -ENOMEM;
++
++	if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
++		if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
++			ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg);
++		else
++			ath10k_wmi_peer_assoc_fill_10_2(ar, skb->data, arg);
++	} else {
++		ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg);
++	}
+ 
+ 	ath10k_dbg(ATH10K_DBG_WMI,
+ 		   "wmi peer assoc vdev %d addr %pM (%s)\n",
+@@ -3532,6 +3932,7 @@ int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif)
+ 	cmd->msdu_id = 0;
+ 	cmd->frame_control = __cpu_to_le32(fc);
+ 	cmd->flags = 0;
++	cmd->antenna_mask = __cpu_to_le32(WMI_BCN_TX_REF_DEF_ANTENNA);
+ 
+ 	if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero)
+ 		cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO);
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
+index e93df2c..c9ac11c 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.h
++++ b/drivers/net/wireless/ath/ath10k/wmi.h
+@@ -803,6 +803,159 @@ enum wmi_10x_event_id {
+ 	WMI_10X_PDEV_UTF_EVENTID = WMI_10X_END_EVENTID-1,
+ };
+ 
++enum wmi_10_2_cmd_id {
++	WMI_10_2_START_CMDID = 0x9000,
++	WMI_10_2_END_CMDID = 0x9FFF,
++	WMI_10_2_INIT_CMDID,
++	WMI_10_2_START_SCAN_CMDID = WMI_10_2_START_CMDID,
++	WMI_10_2_STOP_SCAN_CMDID,
++	WMI_10_2_SCAN_CHAN_LIST_CMDID,
++	WMI_10_2_ECHO_CMDID,
++	WMI_10_2_PDEV_SET_REGDOMAIN_CMDID,
++	WMI_10_2_PDEV_SET_CHANNEL_CMDID,
++	WMI_10_2_PDEV_SET_PARAM_CMDID,
++	WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID,
++	WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID,
++	WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID,
++	WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID,
++	WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID,
++	WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID,
++	WMI_10_2_PDEV_SET_QUIET_MODE_CMDID,
++	WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID,
++	WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID,
++	WMI_10_2_VDEV_CREATE_CMDID,
++	WMI_10_2_VDEV_DELETE_CMDID,
++	WMI_10_2_VDEV_START_REQUEST_CMDID,
++	WMI_10_2_VDEV_RESTART_REQUEST_CMDID,
++	WMI_10_2_VDEV_UP_CMDID,
++	WMI_10_2_VDEV_STOP_CMDID,
++	WMI_10_2_VDEV_DOWN_CMDID,
++	WMI_10_2_VDEV_STANDBY_RESPONSE_CMDID,
++	WMI_10_2_VDEV_RESUME_RESPONSE_CMDID,
++	WMI_10_2_VDEV_SET_PARAM_CMDID,
++	WMI_10_2_VDEV_INSTALL_KEY_CMDID,
++	WMI_10_2_VDEV_SET_DSCP_TID_MAP_CMDID,
++	WMI_10_2_PEER_CREATE_CMDID,
++	WMI_10_2_PEER_DELETE_CMDID,
++	WMI_10_2_PEER_FLUSH_TIDS_CMDID,
++	WMI_10_2_PEER_SET_PARAM_CMDID,
++	WMI_10_2_PEER_ASSOC_CMDID,
++	WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID,
++	WMI_10_2_PEER_UPDATE_WDS_ENTRY_CMDID,
++	WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID,
++	WMI_10_2_PEER_MCAST_GROUP_CMDID,
++	WMI_10_2_BCN_TX_CMDID,
++	WMI_10_2_BCN_PRB_TMPL_CMDID,
++	WMI_10_2_BCN_FILTER_RX_CMDID,
++	WMI_10_2_PRB_REQ_FILTER_RX_CMDID,
++	WMI_10_2_MGMT_TX_CMDID,
++	WMI_10_2_ADDBA_CLEAR_RESP_CMDID,
++	WMI_10_2_ADDBA_SEND_CMDID,
++	WMI_10_2_ADDBA_STATUS_CMDID,
++	WMI_10_2_DELBA_SEND_CMDID,
++	WMI_10_2_ADDBA_SET_RESP_CMDID,
++	WMI_10_2_SEND_SINGLEAMSDU_CMDID,
++	WMI_10_2_STA_POWERSAVE_MODE_CMDID,
++	WMI_10_2_STA_POWERSAVE_PARAM_CMDID,
++	WMI_10_2_STA_MIMO_PS_MODE_CMDID,
++	WMI_10_2_DBGLOG_CFG_CMDID,
++	WMI_10_2_PDEV_DFS_ENABLE_CMDID,
++	WMI_10_2_PDEV_DFS_DISABLE_CMDID,
++	WMI_10_2_PDEV_QVIT_CMDID,
++	WMI_10_2_ROAM_SCAN_MODE,
++	WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD,
++	WMI_10_2_ROAM_SCAN_PERIOD,
++	WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
++	WMI_10_2_ROAM_AP_PROFILE,
++	WMI_10_2_OFL_SCAN_ADD_AP_PROFILE,
++	WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE,
++	WMI_10_2_OFL_SCAN_PERIOD,
++	WMI_10_2_P2P_DEV_SET_DEVICE_INFO,
++	WMI_10_2_P2P_DEV_SET_DISCOVERABILITY,
++	WMI_10_2_P2P_GO_SET_BEACON_IE,
++	WMI_10_2_P2P_GO_SET_PROBE_RESP_IE,
++	WMI_10_2_AP_PS_PEER_PARAM_CMDID,
++	WMI_10_2_AP_PS_PEER_UAPSD_COEX_CMDID,
++	WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID,
++	WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID,
++	WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
++	WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
++	WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
++	WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
++	WMI_10_2_PDEV_SUSPEND_CMDID,
++	WMI_10_2_PDEV_RESUME_CMDID,
++	WMI_10_2_ADD_BCN_FILTER_CMDID,
++	WMI_10_2_RMV_BCN_FILTER_CMDID,
++	WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID,
++	WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID,
++	WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
++	WMI_10_2_WOW_ENABLE_CMDID,
++	WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
++	WMI_10_2_RTT_MEASREQ_CMDID,
++	WMI_10_2_RTT_TSF_CMDID,
++	WMI_10_2_RTT_KEEPALIVE_CMDID,
++	WMI_10_2_PDEV_SEND_BCN_CMDID,
++	WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID,
++	WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID,
++	WMI_10_2_REQUEST_STATS_CMDID,
++	WMI_10_2_GPIO_CONFIG_CMDID,
++	WMI_10_2_GPIO_OUTPUT_CMDID,
++	WMI_10_2_VDEV_RATEMASK_CMDID,
++	WMI_10_2_PDEV_SMART_ANT_ENABLE_CMDID,
++	WMI_10_2_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID,
++	WMI_10_2_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID,
++	WMI_10_2_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID,
++	WMI_10_2_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID,
++	WMI_10_2_FORCE_FW_HANG_CMDID,
++	WMI_10_2_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID,
++	WMI_10_2_PDEV_SET_CTL_TABLE_CMDID,
++	WMI_10_2_PDEV_SET_MIMOGAIN_TABLE_CMDID,
++	WMI_10_2_PDEV_RATEPWR_TABLE_CMDID,
++	WMI_10_2_PDEV_RATEPWR_CHAINMSK_TABLE_CMDID,
++	WMI_10_2_PDEV_UTF_CMDID = WMI_10_2_END_CMDID - 1,
++};
++
++enum wmi_10_2_event_id {
++	WMI_10_2_SERVICE_READY_EVENTID = 0x8000,
++	WMI_10_2_READY_EVENTID,
++	WMI_10_2_DEBUG_MESG_EVENTID,
++	WMI_10_2_START_EVENTID = 0x9000,
++	WMI_10_2_END_EVENTID = 0x9FFF,
++	WMI_10_2_SCAN_EVENTID = WMI_10_2_START_EVENTID,
++	WMI_10_2_ECHO_EVENTID,
++	WMI_10_2_UPDATE_STATS_EVENTID,
++	WMI_10_2_INST_RSSI_STATS_EVENTID,
++	WMI_10_2_VDEV_START_RESP_EVENTID,
++	WMI_10_2_VDEV_STANDBY_REQ_EVENTID,
++	WMI_10_2_VDEV_RESUME_REQ_EVENTID,
++	WMI_10_2_VDEV_STOPPED_EVENTID,
++	WMI_10_2_PEER_STA_KICKOUT_EVENTID,
++	WMI_10_2_HOST_SWBA_EVENTID,
++	WMI_10_2_TBTTOFFSET_UPDATE_EVENTID,
++	WMI_10_2_MGMT_RX_EVENTID,
++	WMI_10_2_CHAN_INFO_EVENTID,
++	WMI_10_2_PHYERR_EVENTID,
++	WMI_10_2_ROAM_EVENTID,
++	WMI_10_2_PROFILE_MATCH,
++	WMI_10_2_DEBUG_PRINT_EVENTID,
++	WMI_10_2_PDEV_QVIT_EVENTID,
++	WMI_10_2_WLAN_PROFILE_DATA_EVENTID,
++	WMI_10_2_RTT_MEASUREMENT_REPORT_EVENTID,
++	WMI_10_2_TSF_MEASUREMENT_REPORT_EVENTID,
++	WMI_10_2_RTT_ERROR_REPORT_EVENTID,
++	WMI_10_2_RTT_KEEPALIVE_EVENTID,
++	WMI_10_2_WOW_WAKEUP_HOST_EVENTID,
++	WMI_10_2_DCS_INTERFERENCE_EVENTID,
++	WMI_10_2_PDEV_TPC_CONFIG_EVENTID,
++	WMI_10_2_GPIO_INPUT_EVENTID,
++	WMI_10_2_PEER_RATECODE_LIST_EVENTID,
++	WMI_10_2_GENERIC_BUFFER_EVENTID,
++	WMI_10_2_MCAST_BUF_RELEASE_EVENTID,
++	WMI_10_2_MCAST_LIST_AGEOUT_EVENTID,
++	WMI_10_2_WDS_PEER_EVENTID,
++	WMI_10_2_PDEV_UTF_EVENTID = WMI_10_2_END_EVENTID - 1,
++};
++
+ enum wmi_phy_mode {
+ 	MODE_11A        = 0,   /* 11a Mode */
+ 	MODE_11G        = 1,   /* 11b/g Mode */
+@@ -1551,6 +1704,16 @@ struct wmi_resource_config_10x {
+ 	__le32 max_frag_entries;
+ } __packed;
+ 
++struct wmi_resource_config_10_2 {
++	struct wmi_resource_config_10x common;
++	__le32 max_peer_ext_stats;
++	__le32 smart_ant_cap; /* 0-disable, 1-enable */
++	__le32 bk_min_free;
++	__le32 be_min_free;
++	__le32 vi_min_free;
++	__le32 vo_min_free;
++	__le32 rx_batchmode; /* 0-disable, 1-enable */
++} __packed;
+ 
+ #define NUM_UNITS_IS_NUM_VDEVS   0x1
+ #define NUM_UNITS_IS_NUM_PEERS   0x2
+@@ -1588,11 +1751,28 @@ struct wmi_init_cmd_10x {
+ 	struct host_memory_chunk host_mem_chunks[1];
+ } __packed;
+ 
++struct wmi_init_cmd_10_2 {
++	struct wmi_resource_config_10_2 resource_config;
++	__le32 num_host_mem_chunks;
++
++	/*
++	 * variable number of host memory chunks.
++	 * This should be the last element in the structure
++	 */
++	struct host_memory_chunk host_mem_chunks[1];
++} __packed;
++
++struct wmi_chan_list_entry {
++	__le16 freq;
++	u8 phy_mode; /* valid for 10.2 only */
++	u8 reserved;
++} __packed;
++
+ /* TLV for channel list */
+ struct wmi_chan_list {
+ 	__le32 tag; /* WMI_CHAN_LIST_TAG */
+ 	__le32 num_chan;
+-	__le32 channel_list[0];
++	struct wmi_chan_list_entry channel_list[0];
+ } __packed;
+ 
+ struct wmi_bssid_list {
+@@ -1821,7 +2001,7 @@ struct wmi_start_scan_arg {
+ 	u32 n_bssids;
+ 
+ 	u8 ie[WLAN_SCAN_PARAMS_MAX_IE_LEN];
+-	u32 channels[64];
++	u16 channels[64];
+ 	struct wmi_ssid_arg ssids[WLAN_SCAN_PARAMS_MAX_SSID];
+ 	struct wmi_bssid_arg bssids[WLAN_SCAN_PARAMS_MAX_BSSID];
+ };
+@@ -2515,6 +2695,19 @@ enum wmi_10x_pdev_param {
+ 	WMI_10X_PDEV_PARAM_BURST_DUR,
+ 	/* Set Bursting Enable*/
+ 	WMI_10X_PDEV_PARAM_BURST_ENABLE,
++
++	/* following are available as of firmware 10.2 */
++	WMI_10X_PDEV_PARAM_SMART_ANTENNA_DEFAULT_ANTENNA,
++	WMI_10X_PDEV_PARAM_IGMPMLD_OVERRIDE,
++	WMI_10X_PDEV_PARAM_IGMPMLD_TID,
++	WMI_10X_PDEV_PARAM_ANTENNA_GAIN,
++	WMI_10X_PDEV_PARAM_RX_DECAP_MODE,
++	WMI_10X_PDEV_PARAM_RX_FILTER,
++	WMI_10X_PDEV_PARAM_SET_MCAST_TO_UCAST_TID,
++	WMI_10X_PDEV_PARAM_PROXY_STA_MODE,
++	WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_MODE,
++	WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_BUFFER,
++	WMI_10X_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER,
+ };
+ 
+ struct wmi_pdev_set_param_cmd {
+@@ -3387,6 +3580,14 @@ enum wmi_10x_vdev_param {
+ 	WMI_10X_VDEV_PARAM_ENABLE_RTSCTS,
+ 
+ 	WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS,
++
++	/* following are available as of firmware 10.2 */
++	WMI_10X_VDEV_PARAM_TX_ENCAP_TYPE,
++	WMI_10X_VDEV_PARAM_CABQ_MAXDUR,
++	WMI_10X_VDEV_PARAM_MFPTEST_SET,
++	WMI_10X_VDEV_PARAM_RTS_FIXED_RATE,
++	WMI_10X_VDEV_PARAM_VHT_SGIMASK,
++	WMI_10X_VDEV_PARAM_VHT80_RATEMASK,
+ };
+ 
+ /* slot time long */
+@@ -3470,6 +3671,11 @@ enum wmi_bcn_tx_ref_flags {
+ 	WMI_BCN_TX_REF_FLAG_DELIVER_CAB = 0x2,
+ };
+ 
++/* TODO: It is unclear why "no antenna" works while any other seemingly valid
++ * chainmask yields no beacons on the air at all.
++ */
++#define WMI_BCN_TX_REF_DEF_ANTENNA 0
++
+ struct wmi_bcn_tx_ref_cmd {
+ 	__le32 vdev_id;
+ 	__le32 data_len;
+@@ -3481,6 +3687,8 @@ struct wmi_bcn_tx_ref_cmd {
+ 	__le32 frame_control;
+ 	/* to control CABQ traffic: WMI_BCN_TX_REF_FLAG_ */
+ 	__le32 flags;
++	/* introduced in 10.2 */
++	__le32 antenna_mask;
+ } __packed;
+ 
+ /* Beacon filter */
+@@ -4053,7 +4261,7 @@ struct wmi_peer_set_q_empty_callback_cmd {
+ /* Maximum listen interval supported by hw in units of beacon interval */
+ #define ATH10K_MAX_HW_LISTEN_INTERVAL 5
+ 
+-struct wmi_peer_assoc_complete_cmd {
++struct wmi_common_peer_assoc_complete_cmd {
+ 	struct wmi_mac_addr peer_macaddr;
+ 	__le32 vdev_id;
+ 	__le32 peer_new_assoc; /* 1=assoc, 0=reassoc */
+@@ -4071,11 +4279,30 @@ struct wmi_peer_assoc_complete_cmd {
+ 	__le32 peer_vht_caps;
+ 	__le32 peer_phymode;
+ 	struct wmi_vht_rate_set peer_vht_rates;
++};
++
++struct wmi_main_peer_assoc_complete_cmd {
++	struct wmi_common_peer_assoc_complete_cmd cmd;
++
+ 	/* HT Operation Element of the peer. Five bytes packed in 2
+ 	 *  INT32 array and filled from lsb to msb. */
+ 	__le32 peer_ht_info[2];
+ } __packed;
+ 
++struct wmi_10_1_peer_assoc_complete_cmd {
++	struct wmi_common_peer_assoc_complete_cmd cmd;
++} __packed;
++
++#define WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX_LSB 0
++#define WMI_PEER_ASSOC_INFO0_MAX_MCS_IDX_MASK 0x0f
++#define WMI_PEER_ASSOC_INFO0_MAX_NSS_LSB 4
++#define WMI_PEER_ASSOC_INFO0_MAX_NSS_MASK 0xf0
++
++struct wmi_10_2_peer_assoc_complete_cmd {
++	struct wmi_common_peer_assoc_complete_cmd cmd;
++	__le32 info0; /* WMI_PEER_ASSOC_INFO0_ */
++} __packed;
++
+ struct wmi_peer_assoc_complete_arg {
+ 	u8 addr[ETH_ALEN];
+ 	u32 vdev_id;
+-- 
+2.0.4
diff --git a/package/backports-custom/backports-custom-0531-rework-peer-accounting.patch b/package/backports-custom/backports-custom-0531-rework-peer-accounting.patch
new file mode 100644
index 0000000..fc64bbf
--- /dev/null
+++ b/package/backports-custom/backports-custom-0531-rework-peer-accounting.patch
@@ -0,0 +1,234 @@
+Michal Kazior michal.kazior at tieto.com 
+Fri Apr 4 07:37:42 EDT 2014
+
+It was troublesome to iterate over peers within a
+sleepable context (e.g. while holding conf_mutex).
+This will be necessary for some upcomming changes
+to tx flushing.
+
+Making peer allocation and initial setup
+ar->conf_mutex bound instead ar->data_lock solves
+the problem.
+
+Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
+---
+ drivers/net/wireless/ath/ath10k/core.h |  5 +++
+ drivers/net/wireless/ath/ath10k/mac.c  | 69 +++++++++++++++++++++++++++++++---
+ drivers/net/wireless/ath/ath10k/txrx.c | 29 +++++++-------
+ 3 files changed, 81 insertions(+), 22 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
+index 8edd6da..61e325a 100644
+--- a/drivers/net/wireless/ath/ath10k/core.h
++++ b/drivers/net/wireless/ath/ath10k/core.h
+@@ -199,9 +199,14 @@ struct ath10k_dfs_stats {
+ #define ATH10K_MAX_NUM_PEER_IDS (1 << 11) /* htt rx_desc limit */
+ 
+ struct ath10k_peer {
++	/* protected by conf_mutex + data_lock */
+ 	struct list_head list;
++
++	/* protected by conf_mutex */
+ 	int vdev_id;
+ 	u8 addr[ETH_ALEN];
++
++	/* protected by data_lock */
+ 	DECLARE_BITMAP(peer_ids, ATH10K_MAX_NUM_PEER_IDS);
+ 	struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
+ };
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index 25362ef..9af3ed5 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -318,28 +318,61 @@ static u8 ath10k_parse_mpdudensity(u8 mpdudensity)
+ 
+ static int ath10k_peer_create(struct ath10k *ar, u32 vdev_id, const u8 *addr)
+ {
++	struct ath10k_peer *peer;
+ 	int ret;
+ 
+ 	lockdep_assert_held(&ar->conf_mutex);
+ 
++	peer = ath10k_peer_find(ar, vdev_id, addr);
++	if (peer) {
++		ath10k_warn("peer %pM on vdev %i already exists\n",
++			    addr, vdev_id);
++		return -EINVAL;
++	}
++
++	peer = kzalloc(sizeof(*peer), GFP_KERNEL);
++	if (!peer) {
++		ath10k_warn("failed to allocate peer %pM on vdev %i: not enough memory\n",
++			    addr, vdev_id);
++		return -ENOMEM;
++	}
++
++	peer->vdev_id = vdev_id;
++	memcpy(peer->addr, addr, ETH_ALEN);
++
++	spin_lock_bh(&ar->data_lock);
++	list_add(&peer->list, &ar->peers);
++	spin_unlock_bh(&ar->data_lock);
++
+ 	ret = ath10k_wmi_peer_create(ar, vdev_id, addr);
+ 	if (ret) {
+ 		ath10k_warn("failed to create wmi peer %pM on vdev %i: %i\n",
+ 			    addr, vdev_id, ret);
+-		return ret;
++		goto err_free;
+ 	}
+ 
+ 	ret = ath10k_wait_for_peer_created(ar, vdev_id, addr);
+ 	if (ret) {
+ 		ath10k_warn("failed to wait for created wmi peer %pM on vdev %i: %i\n",
+ 			    addr, vdev_id, ret);
+-		return ret;
++		goto err_free;
+ 	}
+ 	spin_lock_bh(&ar->data_lock);
+ 	ar->num_peers++;
+ 	spin_unlock_bh(&ar->data_lock);
+ 
+ 	return 0;
++
++err_free:
++	spin_lock_bh(&ar->data_lock);
++	list_del(&peer->list);
++	/* very unlikely, but check anyway */
++	if (!bitmap_empty(peer->peer_ids, ATH10K_MAX_NUM_PEER_IDS))
++		ath10k_warn("removing peer %pM on vdev %i still being mapped in firmware\n",
++			    addr, vdev_id);
++	spin_unlock_bh(&ar->data_lock);
++	kfree(peer);
++	return ret;
+ }
+ 
+ static int ath10k_mac_set_kickout(struct ath10k_vif *arvif)
+@@ -416,22 +449,46 @@ static int ath10k_mac_set_frag(struct ath10k_vif *arvif, u32 value)
+ 
+ static int ath10k_peer_delete(struct ath10k *ar, u32 vdev_id, const u8 *addr)
+ {
++	struct ath10k_peer *peer;
+ 	int ret;
+ 
+ 	lockdep_assert_held(&ar->conf_mutex);
+ 
++	peer = ath10k_peer_find(ar, vdev_id, addr);
++	if (!peer) {
++		ath10k_warn("failed to lookup peer %pM on vdev %i\n",
++			    addr, vdev_id);
++		return -ENOENT;
++	}
++
+ 	ret = ath10k_wmi_peer_delete(ar, vdev_id, addr);
+-	if (ret)
+-		return ret;
++	if (ret) {
++		ath10k_warn("failed to request wmi peer %pM on vdev %i removal: %d\n",
++			    addr, vdev_id, ret);
++		goto out;
++	}
+ 
+ 	ret = ath10k_wait_for_peer_deleted(ar, vdev_id, addr);
+-	if (ret)
+-		return ret;
++	if (ret) {
++		ath10k_warn("failed to wait for wmi peer %pM on vdev %i removal: %d\n",
++			    addr, vdev_id, ret);
++		goto out;
++	}
+ 
+ 	spin_lock_bh(&ar->data_lock);
+ 	ar->num_peers--;
+ 	spin_unlock_bh(&ar->data_lock);
+ 
++out:
++	spin_lock_bh(&ar->data_lock);
++	list_del(&peer->list);
++	if (!bitmap_empty(peer->peer_ids, ATH10K_MAX_NUM_PEER_IDS))
++		ath10k_warn("removing peer %pM on vdev %i still being mapped in firmware\n",
++			    addr, vdev_id);
++	spin_unlock_bh(&ar->data_lock);
++
++	kfree(peer);
++
+ 	return 0;
+ }
+ 
+diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
+index 82669a7..d802569 100644
+--- a/drivers/net/wireless/ath/ath10k/txrx.c
++++ b/drivers/net/wireless/ath/ath10k/txrx.c
+@@ -100,13 +100,13 @@ exit:
+ 		wake_up(&htt->empty_tx_wq);
+ }
+ 
++/* hold conf_mutex for simple iteration, or conf_mutex+data_lock for
++ * modifications */
+ struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
+ 				     const u8 *addr)
+ {
+ 	struct ath10k_peer *peer;
+ 
+-	lockdep_assert_held(&ar->data_lock);
+-
+ 	list_for_each_entry(peer, &ar->peers, list) {
+ 		if (peer->vdev_id != vdev_id)
+ 			continue;
+@@ -139,10 +139,14 @@ static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id,
+ 	int ret;
+ 
+ 	ret = wait_event_timeout(ar->peer_mapping_wq, ({
+-			bool mapped;
++			struct ath10k_peer *peer;
++			bool mapped = false;
+ 
+ 			spin_lock_bh(&ar->data_lock);
+-			mapped = !!ath10k_peer_find(ar, vdev_id, addr);
++			peer = ath10k_peer_find(ar, vdev_id, addr);
++			if (peer)
++				mapped = !bitmap_empty(peer->peer_ids,
++						       ATH10K_MAX_NUM_PEER_IDS);
+ 			spin_unlock_bh(&ar->data_lock);
+ 
+ 			mapped == expect_mapped;
+@@ -173,20 +177,16 @@ void ath10k_peer_map_event(struct ath10k_htt *htt,
+ 	spin_lock_bh(&ar->data_lock);
+ 	peer = ath10k_peer_find(ar, ev->vdev_id, ev->addr);
+ 	if (!peer) {
+-		peer = kzalloc(sizeof(*peer), GFP_ATOMIC);
+-		if (!peer)
+-			goto exit;
+-
+-		peer->vdev_id = ev->vdev_id;
+-		memcpy(peer->addr, ev->addr, ETH_ALEN);
+-		list_add(&peer->list, &ar->peers);
+-		wake_up(&ar->peer_mapping_wq);
++		ath10k_warn("failed to map peer %pM on vdev %i: no such entry\n",
++			    ev->addr, ev->vdev_id);
++		goto exit;
+ 	}
+ 
+ 	ath10k_dbg(ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n",
+ 		   ev->vdev_id, ev->addr, ev->peer_id);
+ 
+ 	set_bit(ev->peer_id, peer->peer_ids);
++	wake_up(&ar->peer_mapping_wq);
+ exit:
+ 	spin_unlock_bh(&ar->data_lock);
+ }
+@@ -210,11 +210,8 @@ void ath10k_peer_unmap_event(struct ath10k_htt *htt,
+ 
+ 	clear_bit(ev->peer_id, peer->peer_ids);
+ 
+-	if (bitmap_empty(peer->peer_ids, ATH10K_MAX_NUM_PEER_IDS)) {
+-		list_del(&peer->list);
+-		kfree(peer);
++	if (bitmap_empty(peer->peer_ids, ATH10K_MAX_NUM_PEER_IDS))
+ 		wake_up(&ar->peer_mapping_wq);
+-	}
+ 
+ exit:
+ 	spin_unlock_bh(&ar->data_lock);
+-- 
+1.8.5.3
diff --git a/package/backports-custom/backports-custom-0531-wmi-htc-tx-credit-starvation.patch b/package/backports-custom/backports-custom-0531-wmi-htc-tx-credit-starvation.patch
new file mode 100644
index 0000000..7caa5b3
--- /dev/null
+++ b/package/backports-custom/backports-custom-0531-wmi-htc-tx-credit-starvation.patch
@@ -0,0 +1,196 @@
+Michal Kazior michal.kazior at tieto.com 
+Wed Apr 9 06:48:48 EDT 2014
+
+Each WMI management Tx consumes 1 HTC Tx credit
+and doesn't replenish it until the frame is
+actually transmitted out of firmware's Tx queues.
+
+If associated client was asleep and has gone out
+of range then unicast frames won't be released for
+FW/HW queues for a while (10 seconds per
+observation). This means that if more management
+frames are queued then HTC Tx credits are drained
+to 0 and no other commands can be submitted
+including beacons and peer removal.
+
+This could in turn result in clients disconnecting
+due to their beacon loss and may trigger spurious
+sta kickouts because wmi peer removal command may
+never reach firmware during disassociation.
+
+This could happen, e.g. when disconnecting
+client (hostapd inactivity) that has gone away
+while asleep when acting as AP.
+
+As a workaround flush frames that can potentialy
+get stuck in FW Tx queues.
+
+Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
+---
+ drivers/net/wireless/ath/ath10k/mac.c | 96 +++++++++++++++++++++++++++++++++++
+ drivers/net/wireless/ath/ath10k/wmi.c |  5 --
+ drivers/net/wireless/ath/ath10k/wmi.h |  3 ++
+ 3 files changed, 99 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index 58ec5a7..5cfbf88 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -2076,9 +2076,67 @@ void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar)
+ 	}
+ }
+ 
++static void ath10k_mgmt_tx_flush(struct ath10k *ar, struct sk_buff *skb)
++{
++	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
++	struct ieee80211_sta *sta;
++	struct ath10k_vif *arvif;
++	u8 *da = ieee80211_get_DA(hdr);
++	u8 vdev_id = ATH10K_SKB_CB(skb)->vdev_id;
++	u32 bcn_intval = 0;
++	unsigned int msecs;
++	int ret;
++
++	lockdep_assert_held(&ar->conf_mutex);
++
++	if (!is_unicast_ether_addr(da))
++		return;
++
++	rcu_read_lock();
++	sta = ieee80211_find_sta_by_ifaddr(ar->hw, da, NULL);
++	rcu_read_unlock();
++
++	/*
++	 * FW Tx queues can be paused only for associated peers. Since this is
++	 * a workaround just assume worst case if station simply entry exists.
++	 */
++	if (!sta)
++		return;
++
++	list_for_each_entry(arvif, &ar->arvifs, list) {
++		if (arvif->vdev_id == vdev_id) {
++			bcn_intval = arvif->beacon_interval;
++			break;
++		}
++	}
++
++	if (!bcn_intval)
++		return;
++
++	/*
++	 * Wait 2 beacon intervals before flushing so stations that are
++	 * asleep but are actually still in range have a chance to see
++	 * updated PVB, wake up and fetch the frame. There's no other way of
++	 * synchronizing other than sleeping because there's no tx completion
++	 * indication event for WMI management tx.
++	 */
++	msecs = 2 * arvif->beacon_interval * 1024 / 1000;
++	ath10k_dbg(ATH10K_DBG_MAC,
++		   "mac flushing peer %pM on vdev %i mgmt tid for unicast mgmt (%d msecs)\n",
++		   da, vdev_id, msecs);
++	msleep(msecs);
++
++	ret = ath10k_wmi_peer_flush(ar, vdev_id, da,
++				    WMI_PEER_TID_MGMT_MASK);
++	if (ret)
++		ath10k_warn("failed to flush peer %pM mgmt tid: %d\n",
++			    da, ret);
++}
++
+ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
+ {
+ 	struct ath10k *ar = container_of(work, struct ath10k, wmi_mgmt_tx_work);
++	struct ieee80211_tx_info *info;
+ 	struct sk_buff *skb;
+ 	int ret;
+ 
+@@ -2087,12 +2145,50 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
+ 		if (!skb)
+ 			break;
+ 
++		mutex_lock(&ar->conf_mutex);
++
+ 		ret = ath10k_wmi_mgmt_tx(ar, skb);
+ 		if (ret) {
+ 			ath10k_warn("failed to transmit management frame via WMI: %d\n",
+ 				    ret);
++			mutex_unlock(&ar->conf_mutex);
+ 			ieee80211_free_txskb(ar->hw, skb);
++			continue;
+ 		}
++
++		/*
++		 * Each WMI management Tx consumes 1 HTC Tx credit and doesn't
++		 * replenish it until the frame is actually transmitted out of
++		 * firmware's Tx queues.
++		 *
++		 * If associated client was asleep and has gone out of range
++		 * then unicast frames won't be released for FW/HW queues for a
++		 * while (10 seconds per observation). This means that if more
++		 * management frames are queued then HTC Tx credits are drained
++		 * to 0 and no other commands can be submitted including
++		 * beacons and peer removal.
++		 *
++		 * This could in turn result in clients disconnecting due to
++		 * their beacon loss and may trigger spurious sta kickouts
++		 * because wmi peer removal command may never reach firmware
++		 * during disassociation.
++		 *
++		 * This could happen, e.g. when disconnecting client that has
++		 * gone away while asleep.
++		 *
++		 * As a workaround flush unicast management frames that can
++		 * possibly be buffered.
++		 *
++		 * Note: This is a deficiency in design of WMI_MGMT_TX command.
++		 */
++		ath10k_mgmt_tx_flush(ar, skb);
++
++		mutex_unlock(&ar->conf_mutex);
++
++		/* there's no way to get ACK so just assume it's acked */
++		info = IEEE80211_SKB_CB(skb);
++		info->flags |= IEEE80211_TX_STAT_ACK;
++		ieee80211_tx_status(ar->hw, skb);
+ 	}
+ }
+ 
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index d4b48ef..3b270a4 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -637,7 +637,6 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
+ 	struct wmi_mgmt_tx_cmd *cmd;
+ 	struct ieee80211_hdr *hdr;
+ 	struct sk_buff *wmi_skb;
+-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ 	int len;
+ 	u16 fc;
+ 
+@@ -673,10 +672,6 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
+ 	if (ret)
+ 		return ret;
+ 
+-	/* TODO: report tx status to mac80211 - temporary just ACK */
+-	info->flags |= IEEE80211_TX_STAT_ACK;
+-	ieee80211_tx_status_irqsafe(ar->hw, skb);
+-
+ 	return ret;
+ }
+ 
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
+index ae83822..90fe2e9 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.h
++++ b/drivers/net/wireless/ath/ath10k/wmi.h
+@@ -3844,6 +3844,9 @@ struct wmi_peer_delete_cmd {
+ 	struct wmi_mac_addr peer_macaddr;
+ } __packed;
+ 
++#define WMI_PEER_TID_MGMT 17
++#define WMI_PEER_TID_MGMT_MASK BIT(WMI_PEER_TID_MGMT)
++
+ struct wmi_peer_flush_tids_cmd {
+ 	__le32 vdev_id;
+ 	struct wmi_mac_addr peer_macaddr;
+-- 
+1.8.5.3
diff --git a/package/backports-custom/backports-custom-0532-wait-for-mgmt-tx-when-flushing.patch b/package/backports-custom/backports-custom-0532-wait-for-mgmt-tx-when-flushing.patch
new file mode 100644
index 0000000..9096224
--- /dev/null
+++ b/package/backports-custom/backports-custom-0532-wait-for-mgmt-tx-when-flushing.patch
@@ -0,0 +1,66 @@
+Michal Kazior michal.kazior at tieto.com 
+Fri Apr 4 07:37:43 EDT 2014
+
+The 10.1 firmware uses WMI to Tx management frames
+but ath10k_flush() didn't care. This could lead to
+some frames not being sent.
+
+Although there are no Tx completions for WMI
+mangement frames it's still better to at least
+wait for ath10k queue to be drained.
+
+Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
+---
+ drivers/net/wireless/ath/ath10k/mac.c | 21 +++++++++++++++++----
+ 1 file changed, 17 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index 9af3ed5..47b3574 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -3766,19 +3766,27 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
+ 
+ 	mutex_lock(&ar->conf_mutex);
+ 
+-	if (ar->state == ATH10K_STATE_WEDGED)
++	if (ar->state == ATH10K_STATE_WEDGED) {
++		ret = -EBUSY;
+ 		goto skip;
++	}
+ 
+ 	ret = wait_event_timeout(ar->htt.empty_tx_wq, ({
+-			bool empty;
++			bool htt_empty, wmi_empty;
++			unsigned long flags;
+ 
+ 			spin_lock_bh(&ar->htt.tx_lock);
+-			empty = (ar->htt.num_pending_tx == 0);
++			htt_empty = (ar->htt.num_pending_tx == 0);
+ 			spin_unlock_bh(&ar->htt.tx_lock);
+ 
++			spin_lock_irqsave(&ar->wmi_mgmt_tx_queue.lock, flags);
++			wmi_empty = skb_queue_len(&ar->wmi_mgmt_tx_queue) == 0;
++			spin_unlock_irqrestore(&ar->wmi_mgmt_tx_queue.lock,
++					       flags);
++
+ 			skip = (ar->state == ATH10K_STATE_WEDGED);
+ 
+-			(empty || skip);
++			((htt_empty && wmi_empty) || skip);
+ 		}), ATH10K_FLUSH_TIMEOUT_HZ);
+ 
+ 	if (ret <= 0 || skip)
+@@ -3787,6 +3795,11 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
+ 
+ skip:
+ 	mutex_unlock(&ar->conf_mutex);
++
++	/* empty mgmt tx queue doesn't mean mgmt tx is flushed because the last
++	 * frame still may be processed by a worker */
++	if (ret > 0)
++		cancel_work_sync(&ar->wmi_mgmt_tx_work);
+ }
+ 
+ /* TODO: Implement this function properly
+-- 
+1.8.5.3
diff --git a/package/backports-custom/backports-custom-0533-improve-tx-flushing.patch b/package/backports-custom/backports-custom-0533-improve-tx-flushing.patch
new file mode 100644
index 0000000..a7f253d
--- /dev/null
+++ b/package/backports-custom/backports-custom-0533-improve-tx-flushing.patch
@@ -0,0 +1,170 @@
+Michal Kazior michal.kazior at tieto.com 
+Fri Apr 4 07:37:44 EDT 2014
+Previous message: [RFT 3/4] ath10k: wait for mgmt tx when flushing too
+Next message: [RFT 4/4] ath10k: improve tx flushing
+Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
+Flushing was prone to timeouts when powersaving
+clients were involved that went missing while
+asleep. The common culprit was NullFunc frame
+being stuck in FW/HW queues.
+
+Introduce a two-pass flushing with WMI flush
+commands interleaved to force frame drops if
+necessary. This allows for a decreased flush
+timeout time and should get rid of some warnings.
+
+Signed-off-by: Michal Kazior <michal.kazior at tieto.com>
+---
+ drivers/net/wireless/ath/ath10k/core.h |  2 +-
+ drivers/net/wireless/ath/ath10k/mac.c  | 92 +++++++++++++++++++++++++++-------
+ drivers/net/wireless/ath/ath10k/wmi.h  |  1 +
+ 3 files changed, 76 insertions(+), 19 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
+index 61e325a..0d60e70 100644
+--- a/drivers/net/wireless/ath/ath10k/core.h
++++ b/drivers/net/wireless/ath/ath10k/core.h
+@@ -38,7 +38,7 @@
+ 
+ #define ATH10K_SCAN_ID 0
+ #define WMI_READY_TIMEOUT (5 * HZ)
+-#define ATH10K_FLUSH_TIMEOUT_HZ (5*HZ)
++#define ATH10K_FLUSH_TIMEOUT_HZ (1*HZ)
+ #define ATH10K_NUM_CHANS 38
+ 
+ /* Antenna noise floor */
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index 47b3574..77e1370 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -3753,25 +3753,30 @@ static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
+ 	return ret;
+ }
+ 
+-static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
++static int ath10k_flush_all_peer_tids(struct ath10k *ar)
+ {
+-	struct ath10k *ar = hw->priv;
+-	bool skip;
++	struct ath10k_peer *peer;
+ 	int ret;
+ 
+-	/* mac80211 doesn't care if we really xmit queued frames or not
+-	 * we'll collect those frames either way if we stop/delete vdevs */
+-	if (drop)
+-		return;
+-
+-	mutex_lock(&ar->conf_mutex);
++	lockdep_assert_held(&ar->conf_mutex);
+ 
+-	if (ar->state == ATH10K_STATE_WEDGED) {
+-		ret = -EBUSY;
+-		goto skip;
++	list_for_each_entry(peer, &ar->peers, list) {
++		ret = ath10k_wmi_peer_flush(ar, peer->vdev_id, peer->addr,
++					    WMI_PEER_TID_ALL_MASK);
++		if (ret) {
++			ath10k_warn("failed to request peer %pM on vdev %i to flush %08x: %d\n",
++				    peer->addr, peer->vdev_id, WMI_PEER_TID_ALL_MASK, ret);
++			return ret;
++		}
+ 	}
+ 
+-	ret = wait_event_timeout(ar->htt.empty_tx_wq, ({
++	return 0;
++}
++
++static int ath10k_flush_wait(struct ath10k *ar)
++{
++	bool skip;
++	int ret = wait_event_timeout(ar->htt.empty_tx_wq, ({
+ 			bool htt_empty, wmi_empty;
+ 			unsigned long flags;
+ 
+@@ -3789,16 +3794,67 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
+ 			((htt_empty && wmi_empty) || skip);
+ 		}), ATH10K_FLUSH_TIMEOUT_HZ);
+ 
+-	if (ret <= 0 || skip)
+-		ath10k_warn("failed to flush transmit queue (skip %i ar-state %i): %i\n",
+-			    skip, ar->state, ret);
++	if (ret == 0)
++		ret = -ETIMEDOUT;
++	else if (ret > 0)
++		ret = 0;
++
++	if (skip) {
++		ath10k_warn("ignoring flushing result because hardware is wedged\n");
++		ret = -EBUSY;
++	}
++
++	return ret;
++}
++
++static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
++{
++	struct ath10k *ar = hw->priv;
++	int ret;
++
++	mutex_lock(&ar->conf_mutex);
++
++	if (drop) {
++		ret = ath10k_flush_all_peer_tids(ar);
++		if (ret) {
++			ath10k_warn("failed to flush all peer tids: %d\n", ret);
++			goto out;
++		}
++
++		goto out;
++	}
++
++	if (ar->state == ATH10K_STATE_WEDGED) {
++		ath10k_warn("skipping flushing because hardware is wedged\n");
++		ret = -EBUSY;
++		goto out;
++	}
++
++	ret = ath10k_flush_wait(ar);
++	if (ret) {
++		ath10k_dbg(ATH10K_DBG_MAC,
++			   "failed to wait for tx to flush: %d, forcing\n",
++			   ret);
++
++		ret = ath10k_flush_all_peer_tids(ar);
++		if (ret) {
++			ath10k_warn("failed to flush all peer tids: %d\n", ret);
++			goto out;
++		}
++
++		ret = ath10k_flush_wait(ar);
++		if (ret) {
++			ath10k_warn("failed to flush tx: %d\n", ret);
++			goto out;
++		}
++	}
+ 
+-skip:
++out:
+ 	mutex_unlock(&ar->conf_mutex);
+ 
+ 	/* empty mgmt tx queue doesn't mean mgmt tx is flushed because the last
+ 	 * frame still may be processed by a worker */
+-	if (ret > 0)
++	if (ret == 0)
+ 		cancel_work_sync(&ar->wmi_mgmt_tx_work);
+ }
+ 
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
+index 90fe2e9..2b37c4a 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.h
++++ b/drivers/net/wireless/ath/ath10k/wmi.h
+@@ -3846,6 +3846,7 @@ struct wmi_peer_delete_cmd {
+ 
+ #define WMI_PEER_TID_MGMT 17
+ #define WMI_PEER_TID_MGMT_MASK BIT(WMI_PEER_TID_MGMT)
++#define WMI_PEER_TID_ALL_MASK 0xFFFFFFFF
+ 
+ struct wmi_peer_flush_tids_cmd {
+ 	__le32 vdev_id;
+-- 
+1.8.5.3
diff --git a/package/backports-custom/backports-custom-0610-always-ap-scan.patch b/package/backports-custom/backports-custom-0610-always-ap-scan.patch
new file mode 100644
index 0000000..d5eb0de
--- /dev/null
+++ b/package/backports-custom/backports-custom-0610-always-ap-scan.patch
@@ -0,0 +1,27 @@
+From e87391b7b98630b5e8b52aca7a8ce3b4f56f758c Mon Sep 17 00:00:00 2001
+From: Avery Pennarun <apenwarr@gmail.com>
+Date: Wed, 27 Aug 2014 03:20:49 -0400
+Subject: [PATCH] mac80211: allow scan in AP mode even if not "supported" by
+ driver.
+
+This allows us to do background channel scans with ath10k.
+---
+ net/mac80211/cfg.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
+index c6db19e..1f01ded 100644
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -2154,7 +2154,7 @@ static int ieee80211_scan(struct wiphy *wiphy,
+ 		 * the  frames sent while scanning on other channel will be
+ 		 * lost)
+ 		 */
+-		if (sdata->u.ap.beacon &&
++		if (0 && sdata->u.ap.beacon &&
+ 		    (!(wiphy->features & NL80211_FEATURE_AP_SCAN) ||
+ 		     !(req->flags & NL80211_SCAN_FLAG_AP)))
+ 			return -EOPNOTSUPP;
+-- 
+2.1.0.rc2.206.gedb03e5
+
diff --git a/package/backports/backports-0910-ieee80211-phy-attrs.patch b/package/backports/backports-0910-ieee80211-phy-attrs.patch
new file mode 100644
index 0000000..fed5af5
--- /dev/null
+++ b/package/backports/backports-0910-ieee80211-phy-attrs.patch
@@ -0,0 +1,28 @@
+From dff0bcbeefa77c1e9d006041ca247513110e1afb Mon Sep 17 00:00:00 2001
+From: Avery Pennarun <apenwarr@gmail.com>
+Date: Mon, 12 May 2014 20:29:55 -0400
+Subject: [PATCH 1/2] sysfs: register /sys/class/ieee80211/phy attributes even
+ on older kernels.
+
+Otherwise 'iw phy phy0 set antenna ...' gives "no such file or directory."
+---
+ net/wireless/sysfs.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
+index 7d3162b..c5d39ed 100644
+--- a/net/wireless/sysfs.c
++++ b/net/wireless/sysfs.c
+@@ -170,9 +170,7 @@ struct class ieee80211_class = {
+ 
+ int wiphy_sysfs_init(void)
+ {
+-#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0)
+ 	init_ieee80211_attrs();
+-#endif
+ 	return class_register(&ieee80211_class);
+ }
+ 
+-- 
+1.9.1.423.g4596e3a
+
diff --git a/package/backports/backports-250-mwifiex-set-passive-scan.patch b/package/backports/backports-250-mwifiex-set-passive-scan.patch
new file mode 100644
index 0000000..c34d6b0
--- /dev/null
+++ b/package/backports/backports-250-mwifiex-set-passive-scan.patch
@@ -0,0 +1,33 @@
+From ec6a3bfbbbed790f0c937149002f00ddbc1e72f4 Mon Sep 17 00:00:00 2001
+From: Avinash Patil <patila@marvell.com>
+Date: Wed, 27 Aug 2014 19:45:48 +0530
+Subject: [PATCH] mwifiex: set passive scan type for scan requests with no ssid
+
+It was observed that station would sent probe request even when
+scan type has been set as passive during iw scan.
+This was happening because driver sets passive scan type only
+when channel has IEEE80211_CHAN_NO_IR flag set.
+Along with this, add condition to check if no ssids are specified in
+scan request so as to mark such scan request passive.
+
+Signed-off-by: Avinash Patil <patila@marvell.com>
+---
+ drivers/net/wireless/mwifiex/cfg80211.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
+index 68d5e84..22badc7 100644
+--- a/drivers/net/wireless/mwifiex/cfg80211.c
++++ b/drivers/net/wireless/mwifiex/cfg80211.c
+@@ -1973,7 +1973,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
+ 		user_scan_cfg->chan_list[i].chan_number = chan->hw_value;
+ 		user_scan_cfg->chan_list[i].radio_type = chan->band;
+ 
+-		if (chan->flags & IEEE80211_CHAN_NO_IR)
++		if ((chan->flags & IEEE80211_CHAN_NO_IR) || !request->n_ssids)
+ 			user_scan_cfg->chan_list[i].scan_type =
+ 						MWIFIEX_SCAN_TYPE_PASSIVE;
+ 		else
+-- 
+1.8.1.4
+
diff --git a/package/bcm_chromium/bcm_chromium.mk b/package/bcm_chromium/bcm_chromium.mk
index 88f559c..9137b02 100644
--- a/package/bcm_chromium/bcm_chromium.mk
+++ b/package/bcm_chromium/bcm_chromium.mk
@@ -9,7 +9,9 @@
 	bcm_bseav bcm_nexus bcm_common bcm_rockford \
 	google_miniclient \
 	libpng jpeg zlib freetype openssl expat \
-	libcurl libxml2 libxslt fontconfig boost
+	libcurl libxml2 libxslt fontconfig boost \
+	cairo
+
 BCM_CHROMIUM_INSTALL_STAGING=NO
 BCM_CHROMIUM_INSTALL_TARGET=YES
 
@@ -84,6 +86,10 @@
 
 define BCM_CHROMIUM_INSTALL_TARGET_CMDS
 	$(call BCM_COMMON_BUILD_EXTRACT_TARBALL, $(TARGET_DIR))
+	if [ -e "$(TARGET_DIR)/usr/local/bin/webkitGl3/chrome-sandbox" ] ; \
+		then \
+			chmod 4755 "$(TARGET_DIR)/usr/local/bin/webkitGl3/chrome-sandbox"; \
+		fi
 endef
 
 # Since chromium needs dlna, etc. to be rebuilt and reinstalled to its
diff --git a/package/bcm_miracast/Config.in b/package/bcm_miracast/Config.in
index 633a53c..32efb03 100644
--- a/package/bcm_miracast/Config.in
+++ b/package/bcm_miracast/Config.in
@@ -1,4 +1,6 @@
 config BR2_PACKAGE_BCM_MIRACAST
 	bool "Build Broadcom Miracast package"
+	depends on !BR2_PACKAGE_GOOGLE_PLATFORM_ONLY
+	default n
 	select BR2_PACKAGE_BCM_COMMON
 	select BR2_PACKAGE_BCM_ROCKFORD
diff --git a/package/google/Config.in b/package/google/Config.in
index 8c3b6ac..6cb36e5 100644
--- a/package/google/Config.in
+++ b/package/google/Config.in
@@ -34,5 +34,6 @@
 source "package/google/google_dart_vm/Config.in"
 source "package/google/google_oregano/Config.in"
 source "package/google/google_gflags/Config.in"
+source "package/google/google_glog/Config.in"
 source "package/google/google_gfrm200/Config.in"
 endmenu
diff --git a/package/google/google_gflags/google_gflags.mk b/package/google/google_gflags/google_gflags.mk
index c2c56fd..739167b 100644
--- a/package/google/google_gflags/google_gflags.mk
+++ b/package/google/google_gflags/google_gflags.mk
@@ -10,6 +10,7 @@
 
 GOOGLE_GFLAGS_DIR = $(BUILD_DIR)/google_gflags-$(GOOGLE_GFLAGS_VERSION)
 GOOGLE_GFLAGS_INSTALL_STAGING = YES
+GOOGLE_GFLAGS_INSTALL_TARGET = YES
 GOOGLE_GFLAGS_CONF_OPT = -DGFLAGS_NAMESPACE=google -DBUILD_SHARED_LIBS=ON
 
 $(eval $(call CMAKETARGETS))
diff --git a/package/google/google_glog/Config.in b/package/google/google_glog/Config.in
new file mode 100644
index 0000000..7cf9bcd
--- /dev/null
+++ b/package/google/google_glog/Config.in
@@ -0,0 +1,5 @@
+config BR2_PACKAGE_GOOGLE_GLOG
+	bool "google_glog"
+	select BR2_PACKAGE_GOOGLE_GFLAGS
+	help
+	  Enables Glog library
diff --git a/package/google/google_glog/google_glog.mk b/package/google/google_glog/google_glog.mk
new file mode 100644
index 0000000..feaf8da
--- /dev/null
+++ b/package/google/google_glog/google_glog.mk
@@ -0,0 +1,9 @@
+GOOGLE_GLOG_SITE = https://google-glog.googlecode.com/files/
+GOOGLE_GLOG_VERSION = 0.3.3
+GOOGLE_GLOG_SOURCE = glog-$(GOOGLE_GLOG_VERSION).tar.gz
+GOOGLE_GLOG_INSTALL_STAGING = YES
+GOOGLE_GLOG_INSTALL_TARGET = YES
+GOOGLE_GLOG_DEPENDENCIES= google_gflags
+
+$(eval $(call AUTOTARGETS))
+$(eval $(call AUTOTARGETS,host))
diff --git a/package/google/google_miniclient/runminiclient b/package/google/google_miniclient/runminiclient
index 5762ee6..8e1c342 100755
--- a/package/google/google_miniclient/runminiclient
+++ b/package/google/google_miniclient/runminiclient
@@ -22,7 +22,7 @@
     read uimode uiserver uires uiremote < /config/uitype
     if [ "$uimode" = "extender" ] ; then
       if [ "$uiserver" = "auto" ] ; then
-        SERVER=`/app/client/miniclient`
+        SERVER=/app/client/miniclient
       else
         SERVER=$uiserver
       fi
@@ -73,7 +73,8 @@
     miniclient)
       rm -f /tmp/gpio/ledcontrol/waitpower
       [ -n "$SERVER_MAC" ] && [ ! -e /tmp/goalone ] && ether-wake $SERVER_MAC
-      ./miniclient $opts "$SERVER"
+      # miniclient is realtime sensitive, so run it on second CPU
+      try_taskset 2 ./miniclient $opts "$SERVER"
       mcstate=$?
       update_server
       if [ "$mcstate" != "0" ]; then
diff --git a/package/google/google_platform/Config.in b/package/google/google_platform/Config.in
index 30e7309..d691b5d 100644
--- a/package/google/google_platform/Config.in
+++ b/package/google/google_platform/Config.in
@@ -66,6 +66,8 @@
 	select BR2_PACKAGE_MEMSTAT
 	select BR2_PACKAGE_MEMTESTER
 	select BR2_PACKAGE_NETPERF
+	select BR2_PACKAGE_RSYNC
+	select BR2_PACKAGE_SSHFS
 	select BR2_PACKAGE_STRACE
 	select BR2_PACKAGE_TCPDUMP
 	select BR2_PACKAGE_TCPDUMP_SMB
@@ -143,7 +145,6 @@
 	select BR2_PACKAGE_GOOGLE_TVSTREAMPARSER
 	select BR2_PACKAGE_BCM_CHROMIUM if BR2_mipsel
 	select BR2_PACKAGE_BCM_DIRECTFB if BR2_mipsel
-	select BR2_PACKAGE_BCM_DRIVER_WIFI if BR2_mipsel
 	select BR2_PACKAGE_BCM_BSEAV if BR2_mipsel
 	select BR2_PACKAGE_BCM_NEXUS if BR2_mipsel
 	select BR2_PACKAGE_BCM_NETFLIX if BR2_mipsel
@@ -154,5 +155,4 @@
 	select BR2_PACKAGE_CAIRO_SVG
 	select BR2_PACKAGE_DIRECTFB
 	select BR2_PACKAGE_LIBPROJECTM
-	select BR2_PACKAGE_BCM_MIRACAST
 	select BR2_PACKAGE_BOOST
diff --git a/package/google/google_sageserver/Sage.properties.defaults.base b/package/google/google_sageserver/Sage.properties.defaults.base
index d8c4576..1583163 100644
--- a/package/google/google_sageserver/Sage.properties.defaults.base
+++ b/package/google/google_sageserver/Sage.properties.defaults.base
@@ -401,3 +401,5 @@
 wifi_sampling_rate=86400000
 fully_reimport_playlists_every_scan=true
 fiber/vod/TrailerPark/Enable=false
+linux/enable_progressive_deletes=true
+linux/progressive_delete_increment=134217728
diff --git a/package/google/google_sageserver/google_sageserver.mk b/package/google/google_sageserver/google_sageserver.mk
index 04f584e..b756212 100644
--- a/package/google/google_sageserver/google_sageserver.mk
+++ b/package/google/google_sageserver/google_sageserver.mk
@@ -3,7 +3,7 @@
 
 ifeq ($(BR2_mipsel),y)
 	GOOGLE_SAGESERVER_DEPENDENCIES += google_skelmir
-	STANDARD_JAR_PATH=$(GOOGLE_SKELMIR_DIR)/mipsel-5k-linux-uclibc/development/lib/Standard.jar
+	STANDARD_JAR_PATH=$(GOOGLE_SKELMIR_DIR)/mipsel-5k-linux-uclibc/Development/Standard.jar
 else ifeq ($(BR2_arm),y)
 	GOOGLE_SAGESERVER_DEPENDENCIES += google_skelmir
 	STANDARD_JAR_PATH=$(GOOGLE_SKELMIR_DIR)/arm-v7l-linux-gnueabi/development/lib/Standard.jar
diff --git a/package/google/google_sageserver/runsage b/package/google/google_sageserver/runsage
index 8d7e8a1..7876530 100755
--- a/package/google/google_sageserver/runsage
+++ b/package/google/google_sageserver/runsage
@@ -93,6 +93,11 @@
   cat SageClient.properties.defaults.analytics
 ) >/tmp/Sage.properties.defaults
 
+BOXTYPE=`cat /etc/platform`
+if [ "GFHD100" = "$BOXTYPE" ] ; then
+  echo "fiber/miracast/enable=true" >> /tmp/Sage.properties.defaults
+fi
+
 read junk1 memtotal junk2 </proc/meminfo
 echo "System memory: $memtotal kb" >&2
 if [ "$memtotal" -le 524288 ]; then
diff --git a/package/google/google_skelmir/google_skelmir.mk b/package/google/google_skelmir/google_skelmir.mk
index 7fcefc2..080c682 100644
--- a/package/google/google_skelmir/google_skelmir.mk
+++ b/package/google/google_skelmir/google_skelmir.mk
@@ -1,12 +1,13 @@
 GOOGLE_SKELMIR_SITE = repo://vendor/skelmir/vm
 
-SKELMIR_BIN=bin/siege
-SKELMIR_LIBDIR=lib
-
 ifeq ($(BR2_mipsel),y)
 SKELMIR_ARCH=mipsel-5k-linux-uclibc
+SKELMIR_BIN=Binaries/siege
+SKELMIR_LIBDIR=Binaries/Libraries
 else ifeq ($(BR2_arm),y)
 SKELMIR_ARCH=arm-v7l-linux-gnueabi
+SKELMIR_BIN=bin/siege
+SKELMIR_LIBDIR=lib
 else
 SKELMIR_ARCH=unknown-skelmir-arch
 endif
@@ -20,6 +21,7 @@
 		$(TARGET_DIR)/app/sage/skelmir/lib/zi
 	cp -f $(@D)/$(SKELMIR_ARCH)/$(SKELMIR_BIN) \
 		$(TARGET_DIR)/app/sage/skelmir/siege
+	ln -sf lib $(TARGET_DIR)/app/sage/skelmir/Libraries
 endef
 
 $(eval $(call GENTARGETS))
diff --git a/package/hostapd/hostapd-100-excessive-logging.patch b/package/hostapd/hostapd-100-excessive-logging.patch
new file mode 100644
index 0000000..779a6e9
--- /dev/null
+++ b/package/hostapd/hostapd-100-excessive-logging.patch
@@ -0,0 +1,79 @@
+From 24fbee95160c3c123fff047702ab9b1ddd9bf5ae Mon Sep 17 00:00:00 2001
+From: Denton Gentry <dgentry@google.com>
+Date: Thu, 7 Aug 2014 12:42:56 -0700
+Subject: [PATCH] Suppress excessive logging.
+
+---
+ src/ap/drv_callbacks.c       |  4 ++++
+ src/drivers/driver_nl80211.c | 12 ++++++------
+ 2 files changed, 10 insertions(+), 6 deletions(-)
+
+diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
+index fb095ef..cba37c2 100644
+--- a/src/ap/drv_callbacks.c
++++ b/src/ap/drv_callbacks.c
+@@ -946,6 +946,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
+ 		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ)
+ 			level = MSG_EXCESSIVE;
+ 	}
++	if (event == EVENT_TX_STATUS &&
++	    data->tx_status.type == WLAN_FC_TYPE_MGMT) {
++		level = MSG_EXCESSIVE;
++	}
+ 
+ 	wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received",
+ 		event_to_string(event), event);
+diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
+index 7568653..3ccbf59 100644
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -7016,24 +7016,24 @@ static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
+ 
+ 	if (freq == 0 && drv->nlmode == NL80211_IFTYPE_ADHOC) {
+ 		freq = nl80211_get_assoc_freq(drv);
+-		wpa_printf(MSG_DEBUG,
++		wpa_printf(MSG_EXCESSIVE,
+ 			   "nl80211: send_frame - Use assoc_freq=%u for IBSS",
+ 			   freq);
+ 	}
+ 	if (freq == 0) {
+-		wpa_printf(MSG_DEBUG, "nl80211: send_frame - Use bss->freq=%u",
++		wpa_printf(MSG_EXCESSIVE, "nl80211: send_frame - Use bss->freq=%u",
+ 			   bss->freq);
+ 		freq = bss->freq;
+ 	}
+ 
+ 	if (drv->use_monitor) {
+-		wpa_printf(MSG_DEBUG, "nl80211: send_frame(freq=%u bss->freq=%u) -> send_mntr",
++		wpa_printf(MSG_EXCESSIVE, "nl80211: send_frame(freq=%u bss->freq=%u) -> send_mntr",
+ 			   freq, bss->freq);
+ 		return wpa_driver_nl80211_send_mntr(drv, data, len,
+ 						    encrypt, noack);
+ 	}
+ 
+-	wpa_printf(MSG_DEBUG, "nl80211: send_frame -> send_frame_cmd");
++	wpa_printf(MSG_EXCESSIVE, "nl80211: send_frame -> send_frame_cmd");
+ 	res = nl80211_send_frame_cmd(bss, freq, wait_time, data, len,
+ 				     &cookie, no_cck, noack, offchanok);
+ 	if (res == 0 && !noack) {
+@@ -7070,7 +7070,7 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
+ 
+ 	mgmt = (struct ieee80211_mgmt *) data;
+ 	fc = le_to_host16(mgmt->frame_control);
+-	wpa_printf(MSG_DEBUG, "nl80211: send_mlme - noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u fc=0x%x nlmode=%d",
++	wpa_printf(MSG_EXCESSIVE, "nl80211: send_mlme - noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u fc=0x%x nlmode=%d",
+ 		   noack, freq, no_cck, offchanok, wait_time, fc, drv->nlmode);
+ 
+ 	if ((is_sta_interface(drv->nlmode) ||
+@@ -7120,7 +7120,7 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data,
+ 			encrypt = 0;
+ 	}
+ 
+-	wpa_printf(MSG_DEBUG, "nl80211: send_mlme -> send_frame");
++	wpa_printf(MSG_EXCESSIVE, "nl80211: send_mlme -> send_frame");
+ 	return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
+ 					     noack, freq, no_cck, offchanok,
+ 					     wait_time);
+-- 
+2.0.0.526.g5318336
+
diff --git a/package/hostapd/hostapd-fflush-stdout.patch b/package/hostapd/hostapd-101-fflush-stdout.patch
similarity index 100%
rename from package/hostapd/hostapd-fflush-stdout.patch
rename to package/hostapd/hostapd-101-fflush-stdout.patch
diff --git a/package/hostapd/hostapd-use-dev-urandom.patch b/package/hostapd/hostapd-102-use-dev-urandom.patch
similarity index 100%
rename from package/hostapd/hostapd-use-dev-urandom.patch
rename to package/hostapd/hostapd-102-use-dev-urandom.patch
diff --git a/package/hostapd/hostapd-150-logs-to-info-level.patch b/package/hostapd/hostapd-150-logs-to-info-level.patch
new file mode 100644
index 0000000..0aa38db
--- /dev/null
+++ b/package/hostapd/hostapd-150-logs-to-info-level.patch
@@ -0,0 +1,318 @@
+From e08545475088709c086e4656d60924cdbcdd87ba Mon Sep 17 00:00:00 2001
+From: Avery Pennarun <apenwarr@gmail.com>
+Date: Sat, 30 Aug 2014 03:06:37 -0400
+Subject: [PATCH 1/3] Change some debug-level messages to info.
+
+hostapd -d (debug mode) is too verbose.  But without it, it's too terse.
+Set some info-level messages to debug level to try to find a better balance.
+
+Also, remove init error message about rfkill (our system has no rfkill
+switch).  And print out the flags that indicate whether a monitor interface
+is needed, in the hope of someday eliminating it.
+---
+ hostapd/main.c               |  3 ++-
+ src/ap/ap_list.c             |  2 +-
+ src/ap/drv_callbacks.c       |  4 ++--
+ src/ap/iapp.c                |  2 +-
+ src/ap/ieee802_11.c          | 10 +++++-----
+ src/ap/ieee802_1x.c          |  4 ++--
+ src/ap/sta_info.c            | 12 ++++++------
+ src/ap/wpa_auth.c            | 12 ++++++++----
+ src/ap/wpa_auth_glue.c       |  2 +-
+ src/drivers/driver_nl80211.c |  5 ++++-
+ src/drivers/rfkill.c         |  2 +-
+ 11 files changed, 33 insertions(+), 25 deletions(-)
+
+diff --git a/hostapd/main.c b/hostapd/main.c
+index a9d7da5..ab7a8e7 100644
+--- a/hostapd/main.c
++++ b/hostapd/main.c
+@@ -625,7 +625,8 @@ int main(int argc, char *argv[])
+ 	    num_bss_configs == 0)
+ 		usage();
+ 
+-	wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
++	// Not needed on our system since we add a log prefix elsewhere
++	//wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
+ 
+ 	if (log_file)
+ 		wpa_debug_open_file(log_file);
+diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c
+index 287d520..d4fec5b 100644
+--- a/src/ap/ap_list.c
++++ b/src/ap/ap_list.c
+@@ -221,7 +221,7 @@ void ap_list_process_beacon(struct hostapd_iface *iface,
+ 	if (!iface->olbc &&
+ 	    ap_list_beacon_olbc(iface, ap)) {
+ 		iface->olbc = 1;
+-		wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR
++		wpa_printf(MSG_INFO, "OLBC AP detected: " MACSTR
+ 			   " (channel %d) - enable protection",
+ 			   MAC2STR(ap->addr), ap->channel);
+ 		set_beacon++;
+diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
+index cba37c2..f0ea89c 100644
+--- a/src/ap/drv_callbacks.c
++++ b/src/ap/drv_callbacks.c
+@@ -555,7 +555,7 @@ static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
+ 		return;
+ 
+ 	hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
+-		       HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
++		       HOSTAPD_LEVEL_INFO, "authentication OK (FT)");
+ 	sta->flags |= WLAN_STA_AUTH;
+ 
+ 	hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len);
+@@ -931,7 +931,7 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
+ {
+ 	struct hostapd_data *hapd = ctx;
+ #ifndef CONFIG_NO_STDOUT_DEBUG
+-	int level = MSG_DEBUG;
++	int level = MSG_INFO;
+ 
+ 	if (event == EVENT_RX_MGMT && data->rx_mgmt.frame &&
+ 	    data->rx_mgmt.frame_len >= 24) {
+diff --git a/src/ap/iapp.c b/src/ap/iapp.c
+index 9b2900f..0387891 100644
+--- a/src/ap/iapp.c
++++ b/src/ap/iapp.c
+@@ -292,7 +292,7 @@ static void iapp_process_add_notify(struct iapp_data *iapp,
+ 	 * this is not really a reliable verification. */
+ 
+ 	hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
+-		       HOSTAPD_LEVEL_DEBUG,
++		       HOSTAPD_LEVEL_INFO,
+ 		       "Removing STA due to IAPP ADD-notify");
+ 	ap_sta_disconnect(iapp->hapd, sta, NULL, 0);
+ }
+diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
+index ca8db8f..db7f6e6 100644
+--- a/src/ap/ieee802_11.c
++++ b/src/ap/ieee802_11.c
+@@ -245,7 +245,7 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
+ 	}
+ 
+ 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+-		       HOSTAPD_LEVEL_DEBUG,
++		       HOSTAPD_LEVEL_INFO,
+ 		       "authentication OK (shared key)");
+ 	sta->flags |= WLAN_STA_AUTH;
+ 	wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+@@ -314,7 +314,7 @@ static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
+ 		return;
+ 
+ 	hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
+-		       HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
++		       HOSTAPD_LEVEL_INFO, "authentication OK (FT)");
+ 	sta->flags |= WLAN_STA_AUTH;
+ 	mlme_authenticate_indication(hapd, sta);
+ }
+@@ -694,7 +694,7 @@ static void handle_auth(struct hostapd_data *hapd,
+ 	switch (auth_alg) {
+ 	case WLAN_AUTH_OPEN:
+ 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+-			       HOSTAPD_LEVEL_DEBUG,
++			       HOSTAPD_LEVEL_INFO,
+ 			       "authentication OK (open system)");
+ 		sta->flags |= WLAN_STA_AUTH;
+ 		wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+@@ -1463,7 +1463,7 @@ static void handle_disassoc(struct hostapd_data *hapd,
+ 		return;
+ 	}
+ 
+-	wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d",
++	wpa_printf(MSG_INFO, "disassocation: STA=" MACSTR " reason_code=%d",
+ 		   MAC2STR(mgmt->sa),
+ 		   le_to_host16(mgmt->u.disassoc.reason_code));
+ 
+@@ -1511,7 +1511,7 @@ static void handle_deauth(struct hostapd_data *hapd,
+ 		return;
+ 	}
+ 
+-	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "deauthentication: STA=" MACSTR
++	wpa_msg(hapd->msg_ctx, MSG_INFO, "deauthentication: STA=" MACSTR
+ 		" reason_code=%d",
+ 		MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code));
+ 
+diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
+index 035415f..02f0df1 100644
+--- a/src/ap/ieee802_1x.c
++++ b/src/ap/ieee802_1x.c
+@@ -1609,7 +1609,7 @@ void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
+ 		 * request and we cannot continue EAP processing (EAP-Failure
+ 		 * could only be sent if the EAP peer actually replied).
+ 		 */
+-		wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR,
++		wpa_dbg(hapd->msg_ctx, MSG_INFO, "EAP Timeout, STA " MACSTR,
+ 			MAC2STR(sta->addr));
+ 
+ 		sm->eap_if->portEnabled = FALSE;
+@@ -2354,7 +2354,7 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
+ 		 * EAP-FAST with anonymous provisioning, may require another
+ 		 * EAPOL authentication to be started to complete connection.
+ 		 */
+-		wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force "
++		wpa_dbg(hapd->msg_ctx, MSG_INFO, "IEEE 802.1X: Force "
+ 			"disconnection after EAP-Failure");
+ 		/* Add a small sleep to increase likelihood of previously
+ 		 * requested EAP-Failure TX getting out before this should the
+diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
+index 60f0768..6f42088 100644
+--- a/src/ap/sta_info.c
++++ b/src/ap/sta_info.c
+@@ -356,14 +356,14 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
+ 		} else if (inactive_sec < hapd->conf->ap_max_inactivity &&
+ 			   sta->flags & WLAN_STA_ASSOC) {
+ 			/* station activity detected; reset timeout state */
+-			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
++			wpa_msg(hapd->msg_ctx, MSG_INFO,
+ 				"Station " MACSTR " has been active %is ago",
+ 				MAC2STR(sta->addr), inactive_sec);
+ 			sta->timeout_next = STA_NULLFUNC;
+ 			next_time = hapd->conf->ap_max_inactivity + fuzz -
+ 				inactive_sec;
+ 		} else {
+-			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
++			wpa_msg(hapd->msg_ctx, MSG_INFO,
+ 				"Station " MACSTR " has been "
+ 				"inactive too long: %d sec, max allowed: %d",
+ 				MAC2STR(sta->addr), inactive_sec,
+@@ -655,8 +655,8 @@ static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx)
+ void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
+ 			 u16 reason)
+ {
+-	wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
+-		   hapd->conf->iface, MAC2STR(sta->addr));
++	wpa_printf(MSG_INFO, "%s: disassociate STA " MACSTR " (reason=0x%04x)",
++		   hapd->conf->iface, MAC2STR(sta->addr), reason);
+ 	sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
+ 	ap_sta_set_authorized(hapd, sta, 0);
+ 	sta->timeout_next = STA_DEAUTH;
+@@ -693,8 +693,8 @@ static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx)
+ void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
+ 			   u16 reason)
+ {
+-	wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
+-		   hapd->conf->iface, MAC2STR(sta->addr));
++	wpa_printf(MSG_INFO, "%s: deauthenticate STA " MACSTR " (reason=0x%04x)",
++		   hapd->conf->iface, MAC2STR(sta->addr), reason);
+ 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ 	ap_sta_set_authorized(hapd, sta, 0);
+ 	sta->timeout_next = STA_REMOVE;
+diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
+index a9cd6f6..544cb44 100644
+--- a/src/ap/wpa_auth.c
++++ b/src/ap/wpa_auth.c
+@@ -242,7 +242,7 @@ static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
+ 	struct wpa_authenticator *wpa_auth = eloop_ctx;
+ 	struct wpa_group *group;
+ 
+-	wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK");
++	wpa_auth_logger(wpa_auth, NULL, LOGGER_INFO, "rekeying GTK");
+ 	for (group = wpa_auth->group; group; group = group->next) {
+ 		group->GTKReKey = TRUE;
+ 		do {
+@@ -263,7 +263,7 @@ static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
+ 	struct wpa_authenticator *wpa_auth = eloop_ctx;
+ 	struct wpa_state_machine *sm = timeout_ctx;
+ 
+-	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "rekeying PTK");
++	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO, "rekeying PTK");
+ 	wpa_request_new_ptk(sm);
+ 	wpa_sm_step(sm);
+ }
+@@ -637,7 +637,7 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
+ 		return;
+ 
+ 	if (sm->wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
+-		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
++		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+ 				"strict rekeying - force GTK rekey since STA "
+ 				"is leaving");
+ 		eloop_cancel_timeout(wpa_rekey_gtk, sm->wpa_auth, NULL);
+@@ -990,7 +990,7 @@ continue_processing:
+ 			 * Counter update and the station will be allowed to
+ 			 * continue.
+ 			 */
+-			wpa_printf(MSG_DEBUG, "WPA: Reject 4-way handshake to "
++			wpa_printf(MSG_ERROR, "WPA: Reject 4-way handshake to "
+ 				   "collect more entropy for random number "
+ 				   "generation");
+ 			random_mark_pool_ready();
+@@ -1035,6 +1035,8 @@ continue_processing:
+ 		}
+ #ifdef CONFIG_IEEE80211R
+ 		if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) {
++			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
++				"WPA ft_check_msg_2_of_4 failure");
+ 			wpa_sta_disconnect(wpa_auth, sm->addr);
+ 			return;
+ 		}
+@@ -1625,6 +1627,7 @@ SM_STATE(WPA_PTK, DISCONNECT)
+ {
+ 	SM_ENTRY_MA(WPA_PTK, DISCONNECT, wpa_ptk);
+ 	sm->Disconnect = FALSE;
++	wpa_printf(MSG_INFO, "WPA_PTK: disconnect state");
+ 	wpa_sta_disconnect(sm->wpa_auth, sm->addr);
+ }
+ 
+@@ -2157,6 +2160,7 @@ SM_STATE(WPA_PTK, PTKINITDONE)
+ 		int klen = wpa_cipher_key_len(sm->pairwise);
+ 		if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
+ 				     sm->PTK.tk1, klen)) {
++			wpa_printf(MSG_ERROR, "wpa_auth_set_key error");
+ 			wpa_sta_disconnect(sm->wpa_auth, sm->addr);
+ 			return;
+ 		}
+diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
+index 6ee9a4f..a6a2b11 100644
+--- a/src/ap/wpa_auth_glue.c
++++ b/src/ap/wpa_auth_glue.c
+@@ -130,7 +130,7 @@ static void hostapd_wpa_auth_disconnect(void *ctx, const u8 *addr,
+ 					u16 reason)
+ {
+ 	struct hostapd_data *hapd = ctx;
+-	wpa_printf(MSG_DEBUG, "%s: WPA authenticator requests disconnect: "
++	wpa_printf(MSG_INFO, "%s: WPA authenticator requests disconnect: "
+ 		   "STA " MACSTR " reason %d",
+ 		   __func__, MAC2STR(addr), reason);
+ 	ap_sta_disconnect(hapd, NULL, addr, reason);
+diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
+index 3ccbf59..c114e3b 100644
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -3987,6 +3987,9 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
+ 	 * to have everything we need to not need monitor interfaces.
+ 	 */
+ 	drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
++	wpa_printf(MSG_INFO, "monitor mode needed: %d (poll_cmd=%d data_tx_status=%d)",
++		drv->use_monitor, info.poll_command_supported,
++		info.data_tx_status);
+ 
+ 	if (drv->device_ap_sme && drv->use_monitor) {
+ 		/*
+@@ -7246,7 +7249,7 @@ static int wpa_driver_nl80211_set_ap(void *priv,
+ 	if (!msg)
+ 		return -ENOMEM;
+ 
+-	wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
++	wpa_printf(MSG_INFO, "nl80211: Set beacon (beacon_set=%d)",
+ 		   beacon_set);
+ 	if (beacon_set)
+ 		cmd = NL80211_CMD_SET_BEACON;
+diff --git a/src/drivers/rfkill.c b/src/drivers/rfkill.c
+index 45b26c4..f2cd47c 100644
+--- a/src/drivers/rfkill.c
++++ b/src/drivers/rfkill.c
+@@ -110,7 +110,7 @@ struct rfkill_data * rfkill_init(struct rfkill_config *cfg)
+ 	rfkill->cfg = cfg;
+ 	rfkill->fd = open("/dev/rfkill", O_RDONLY);
+ 	if (rfkill->fd < 0) {
+-		wpa_printf(MSG_INFO, "rfkill: Cannot open RFKILL control "
++		wpa_printf(MSG_DEBUG, "rfkill: Cannot open RFKILL control "
+ 			   "device");
+ 		goto fail;
+ 	}
+-- 
+2.1.0.rc2.206.gedb03e5
+
diff --git a/package/hostapd/hostapd-200-alivemon.patch b/package/hostapd/hostapd-200-alivemon.patch
new file mode 100644
index 0000000..e396185
--- /dev/null
+++ b/package/hostapd/hostapd-200-alivemon.patch
@@ -0,0 +1,159 @@
+From cd80d02da128013fb4f40457ba45eeb4651d57d5 Mon Sep 17 00:00:00 2001
+From: Avery Pennarun <apenwarr@gmail.com>
+Date: Sat, 30 Aug 2014 04:30:03 -0400
+Subject: [PATCH] Add a -A (alivemon_path) option.
+
+When set, touches the given filename every few seconds, but only if events
+have been received from the kernel.  You can monitor this to see if the
+hostapd process is alive or not.
+
+Plus, we add a log message that, every few seconds, prints out a total of
+nl80211 events that have been received, and also breaks down some common
+types (notably beacons and probes).
+---
+ hostapd/main.c         |  7 ++++++-
+ src/ap/drv_callbacks.c | 46 +++++++++++++++++++++++++++++++++++++++-------
+ src/ap/hostapd.h       |  2 ++
+ 3 files changed, 47 insertions(+), 8 deletions(-)
+
+diff --git a/hostapd/main.c b/hostapd/main.c
+index ab7a8e7..4f17688 100644
+--- a/hostapd/main.c
++++ b/hostapd/main.c
+@@ -35,6 +35,7 @@ struct hapd_global {
+ };
+ 
+ static struct hapd_global global;
++char *alivemon_path = NULL;
+ 
+ 
+ #ifndef CONFIG_NO_HOSTAPD_LOGGER
+@@ -433,6 +434,7 @@ static void usage(void)
+ 		"options:\n"
+ 		"   -h   show this usage\n"
+ 		"   -d   show more debug messages (-dd for even more)\n"
++		"   -A   alivemonitor file\n"
+ 		"   -B   run daemon in the background\n"
+ 		"   -e   entropy file\n"
+ 		"   -g   global control interface path\n"
+@@ -554,7 +556,7 @@ int main(int argc, char *argv[])
+ 	interfaces.global_ctrl_sock = -1;
+ 
+ 	for (;;) {
+-		c = getopt(argc, argv, "b:Bde:f:hKP:Ttu:vg:G:");
++		c = getopt(argc, argv, "b:A:Bde:f:hKP:Ttu:vg:G:");
+ 		if (c < 0)
+ 			break;
+ 		switch (c) {
+@@ -566,6 +568,9 @@ int main(int argc, char *argv[])
+ 			if (wpa_debug_level > 0)
+ 				wpa_debug_level--;
+ 			break;
++		case 'A':
++			alivemon_path = optarg;
++			break;
+ 		case 'B':
+ 			daemonize++;
+ 			break;
+diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
+index f0ea89c..f86574f 100644
+--- a/src/ap/drv_callbacks.c
++++ b/src/ap/drv_callbacks.c
+@@ -5,7 +5,7 @@
+  * This software may be distributed under the terms of the BSD license.
+  * See README for more details.
+  */
+-
++#define _GNU_SOURCE
+ #include "utils/includes.h"
+ 
+ #include "utils/common.h"
+@@ -32,7 +32,9 @@
+ #include "hw_features.h"
+ #include "dfs.h"
+ #include "beacon.h"
+-
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
+ 
+ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
+ 			const u8 *req_ies, size_t req_ies_len, int reassoc)
+@@ -929,10 +931,16 @@ static void hostapd_event_dfs_nop_finished(struct hostapd_data *hapd,
+ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
+ 			  union wpa_event_data *data)
+ {
++	static struct {
++		int all, beacon, probe_req, tx_status, tx_status_mgmt;
++	} counts;
++	static struct os_reltime last_count_print_time;
++	struct os_reltime now;
+ 	struct hostapd_data *hapd = ctx;
+ #ifndef CONFIG_NO_STDOUT_DEBUG
+ 	int level = MSG_INFO;
+ 
++	counts.all++;
+ 	if (event == EVENT_RX_MGMT && data->rx_mgmt.frame &&
+ 	    data->rx_mgmt.frame_len >= 24) {
+ 		const struct ieee80211_hdr *hdr;
+@@ -940,15 +948,39 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
+ 		hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
+ 		fc = le_to_host16(hdr->frame_control);
+ 		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+-		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
++		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) {
+ 			level = MSG_EXCESSIVE;
++			counts.beacon++;
++		}
+ 		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+-		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ)
++		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) {
++			level = MSG_EXCESSIVE;
++			counts.probe_req++;
++		}
++	}
++	if (event == EVENT_TX_STATUS) {
++		if (data->tx_status.type == WLAN_FC_TYPE_MGMT) {
+ 			level = MSG_EXCESSIVE;
++			counts.tx_status_mgmt++;
++		} else {
++			counts.tx_status++;
++		}
+ 	}
+-	if (event == EVENT_TX_STATUS &&
+-	    data->tx_status.type == WLAN_FC_TYPE_MGMT) {
+-		level = MSG_EXCESSIVE;
++
++	os_get_reltime(&now);
++	if (os_reltime_expired(&now, &last_count_print_time, 5)) {
++		wpa_dbg(hapd->msg_ctx, MSG_INFO,
++			"Events: %d beacon=%d probe=%d tx=%d txm=%d",
++			counts.all, counts.beacon, counts.probe_req,
++			counts.tx_status, counts.tx_status_mgmt);
++		if (counts.all && alivemon_path) {
++			int fd = open(alivemon_path,
++				O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW,
++				0666);
++			if (fd >= 0) close(fd);
++		}
++		last_count_print_time = now;
++		memset(&counts, 0, sizeof(counts));
+ 	}
+ 
+ 	wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received",
+diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
+index bd85c54..6560da2 100644
+--- a/src/ap/hostapd.h
++++ b/src/ap/hostapd.h
+@@ -13,6 +13,8 @@
+ #include "ap_config.h"
+ #include "drivers/driver.h"
+ 
++extern char *alivemon_path;
++
+ struct wpa_ctrl_dst;
+ struct radius_server_data;
+ struct upnp_wps_device_sm;
+-- 
+2.1.0.rc2.206.gedb03e5
+
diff --git a/package/hostapd/hostapd-210-nonzero-exit.patch b/package/hostapd/hostapd-210-nonzero-exit.patch
new file mode 100644
index 0000000..379130a
--- /dev/null
+++ b/package/hostapd/hostapd-210-nonzero-exit.patch
@@ -0,0 +1,39 @@
+From acf5b86bb4d97b4a14731e7c196996a8e30a5397 Mon Sep 17 00:00:00 2001
+From: Avery Pennarun <apenwarr@gmail.com>
+Date: Wed, 3 Sep 2014 02:01:05 -0400
+Subject: [PATCH] Return nonzero exit code if terminate_on_error is set.
+
+Under some conditions, hostapd would abort on error but return a successful
+exit code.
+
+Example steps:
+- hostapd starts and runs, but core dumps.
+- this leaves mon.wlan0 and wlan0 interfaces in a funny state.
+- upon next startup, can't initialize wlan0:
+   nl80211: Failed to set channel (freq=2412): -16 (Device or resource busy)
+   Could not set channel for kernel driver
+   Interface initialization failed
+- this leaves terminate_on_error nonzero because interface didn't init.
+- however, the code then ignores terminate_on_error and just returns 0
+  anyway.
+- a babysitter looking for a successful exit would then not restart it.
+---
+ hostapd/main.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/hostapd/main.c b/hostapd/main.c
+index 4f17688..53fec46 100644
+--- a/hostapd/main.c
++++ b/hostapd/main.c
+@@ -729,7 +729,7 @@ int main(int argc, char *argv[])
+ 		goto out;
+ 	}
+ 
+-	ret = 0;
++	ret = interfaces.terminate_on_error;
+ 
+  out:
+ 	hostapd_global_ctrl_iface_deinit(&interfaces);
+-- 
+2.1.0.rc2.206.gedb03e5
+
diff --git a/package/hostapd/hostapd-gitignore.patch b/package/hostapd/hostapd-gitignore.patch
new file mode 100644
index 0000000..8926892
--- /dev/null
+++ b/package/hostapd/hostapd-gitignore.patch
@@ -0,0 +1,23 @@
+From 17f9eb5a2ad5d7d06e6a004b893224253a86804e Mon Sep 17 00:00:00 2001
+From: Avery Pennarun <apenwarr@gmail.com>
+Date: Sat, 30 Aug 2014 00:31:42 -0400
+Subject: [PATCH 1/4] .gitignore
+
+---
+ .gitignore | 4 ++++
+ 1 file changed, 4 insertions(+)
+ create mode 100644 .gitignore
+
+diff --git a/.gitignore b/.gitignore
+new file mode 100644
+index 0000000..d2ef15f
+--- /dev/null
++++ b/.gitignore
+@@ -0,0 +1,4 @@
++*~
++*.o
++hostapd/hostapd
++hostapd/hostapd_cli
+-- 
+2.1.0.rc2.206.gedb03e5
+
diff --git a/package/minissdpd/S55ssdpd b/package/minissdpd/S55ssdpd
index 2817f77..312501f 100644
--- a/package/minissdpd/S55ssdpd
+++ b/package/minissdpd/S55ssdpd
@@ -1,11 +1,21 @@
 #!/bin/sh
 
+start()
+{
+  babysit 60 setuid nobody minissdpd -i br0 -6 -d 2>&1 | logos ssdpd &
+}
+
+stop()
+{
+  pkillwait minissdpd
+}
+
 case "$1" in
   start)
-    babysit 60 setuid nobody minissdpd -i br0 -6 -d 2>&1 | logos ssdpd &
+    start
     ;;
   stop)
-    pkillwait minissdpd
+    stop
     ;;
   restart)
     stop
diff --git a/package/minissdpd/minissdpd-0002-enquieten-logging.patch b/package/minissdpd/minissdpd-0002-enquieten-logging.patch
new file mode 100644
index 0000000..efce8c7
--- /dev/null
+++ b/package/minissdpd/minissdpd-0002-enquieten-logging.patch
@@ -0,0 +1,48 @@
+From e56859da2097a42fe39553667c09a8fb95a0b323 Mon Sep 17 00:00:00 2001
+From: Denton Gentry <dgentry@google.com>
+Date: Fri, 15 Aug 2014 23:21:17 -0700
+Subject: [PATCH] Adjust logging.
+
+Don't log to the console.
+Remove log messages which are not terribly useful.
+---
+ minissdpd.c | 8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+diff --git a/minissdpd.c b/minissdpd.c
+index 15dd51c..66a002e 100644
+--- a/minissdpd.c
++++ b/minissdpd.c
+@@ -871,11 +871,9 @@ int main(int argc, char * * argv)
+ 	}
+ 
+ 	/* open log */
+-	openlog("minissdpd",
+-	        LOG_CONS|LOG_PID|(debug_flag?LOG_PERROR:0),
++	openlog("minissdpd", LOG_PID|(debug_flag?LOG_PERROR:0),
+ 			LOG_MINISSDPD);
+-	if(!debug_flag) /* speed things up and ignore LOG_INFO and LOG_DEBUG */
+-		setlogmask(LOG_UPTO(LOG_NOTICE));
++	setlogmask(LOG_UPTO(LOG_INFO));
+ 
+ 	if(checkforrunning(pidfilename) < 0)
+ 	{
+@@ -1023,7 +1021,6 @@ int main(int argc, char * * argv)
+ 				/*printf("%.*s", n, buf);*/
+ 				i = ParseSSDPPacket(s_ssdp6, buf, n,
+ 				                    (struct sockaddr *)&sendername6);
+-				syslog(LOG_DEBUG, "** i=%d deltadev=%d **", i, deltadev);
+ 				if(i==0 || (i*deltadev < 0))
+ 				{
+ 					if(deltadev > 0)
+@@ -1054,7 +1051,6 @@ int main(int argc, char * * argv)
+ 				/*printf("%.*s", n, buf);*/
+ 				i = ParseSSDPPacket(s_ssdp, buf, n,
+ 				                    (struct sockaddr *)&sendername);
+-				syslog(LOG_DEBUG, "** i=%d deltadev=%d **", i, deltadev);
+ 				if(i==0 || (i*deltadev < 0))
+ 				{
+ 					if(deltadev > 0)
+-- 
+2.1.0.rc2.206.gedb03e5
+
diff --git a/package/miniupnpd/S80upnpd b/package/miniupnpd/S80upnpd
old mode 100644
new mode 100755
index ed88c11..c1c6125
--- a/package/miniupnpd/S80upnpd
+++ b/package/miniupnpd/S80upnpd
@@ -1,4 +1,4 @@
-#! /bin/sh
+#!/bin/sh
 
 # manage miniupnpd and minissdpd, the IGD/NAT-DMP daemons
 
@@ -11,7 +11,7 @@
 
 start()
 {
-  if [ ! -f $enabler ]; then
+  if [ ! -f "$enabler" ]; then
     echo "$enabler does not exist, refusing to start."
     return
   fi
@@ -33,6 +33,8 @@
   lanipv4=${lanipv4#* inet }
   lanipv4=${lanipv4%%/*}
 
+  version="Google Fiber $(cat /etc/version) UPnP/1.1 MiniUPnPd"
+
   wan=$(activewan)
 
   if [ -z "$wan" ]; then
@@ -40,17 +42,16 @@
     return
   fi
 
-  cmd="miniupnpd -i '$wan' -a '$lanipv4' -u '$uuid' -s '$sn' -m '$model' -z '$friendly' -N"
-  echo "Running: $cmd"
-  eval "$cmd 2>&1 | logos upnpd"
+  set -- \
+      miniupnpd -i "$wan" -a "$lanipv4" -u "$uuid" \
+          -s "$sn" -m "$model" -z "$friendly" -N -d -V "$version"
+  echo "Running:" "$@"
+  babysit 10 "$@" 2>&1 | logos upnpd &
 }
 
 stop()
 {
-  if [ -f /var/run/miniupnpd.pid ]; then
-    kill -TERM $(cat /var/run/miniupnpd.pid)
-    sleep 1
-  fi
+  killpid /var/run/miniupnpd.pid
 }
 
 
diff --git a/package/miniupnpd/miniupnpd-001-cross-compilation.patch b/package/miniupnpd/miniupnpd-001-cross-compilation.patch
new file mode 100644
index 0000000..7f96ff9
--- /dev/null
+++ b/package/miniupnpd/miniupnpd-001-cross-compilation.patch
@@ -0,0 +1,197 @@
+From 3e8b73de8768ac32c76eef866ba47e14e4fb9e84 Mon Sep 17 00:00:00 2001
+From: Denton Gentry <dgentry@google.com>
+Date: Sat, 16 Aug 2014 12:03:13 -0700
+Subject: [PATCH] Better support for cross-compilation.
+
+Allow MINIUPNPD_SERVER_STRING to be set from the command line.
+Previously it was compiling in values from the build system.
+
+Allow OS_NAME and OS_VERSION to be overridden by the Makefile,
+rather than always reflect that of the build system.
+---
+ genconfig.sh | 13 +++++++++++--
+ minissdp.c   | 12 ++++++++----
+ minissdp.h   |  3 +++
+ miniupnpd.c  |  9 +++++++++
+ upnphttp.c   | 11 +++++------
+ 5 files changed, 36 insertions(+), 12 deletions(-)
+
+diff --git a/genconfig.sh b/genconfig.sh
+index 3e72848..8bc7369 100755
+--- a/genconfig.sh
++++ b/genconfig.sh
+@@ -39,8 +39,12 @@ UPNP_VERSION=`date +"%Y%m%d"`
+ LOG_MINIUPNPD="LOG_DAEMON"
+ 
+ # detecting the OS name and version
+-OS_NAME=`uname -s`
+-OS_VERSION=`uname -r`
++if [ -z "$OS_NAME" ]; then
++	OS_NAME=`uname -s`
++fi
++if [ -z "$OS_VERSION" ]; then
++	OS_VERSION=`uname -r`
++fi
+ 
+ # pfSense special case
+ if [ -f /etc/platform ]; then
+@@ -264,6 +268,11 @@ case $OS_NAME in
+ 		FW=ipfw
+ 		OS_URL=http://developer.apple.com/macosx
+ 		;;
++	"Google Fiber")
++		OS_URL=http://www.google.com/fiber
++		echo "#define USE_IFACEWATCHER 1" >> ${CONFIGFILE}
++		FW=netfilter
++		;;
+ 	*)
+ 		echo "Unknown OS : $OS_NAME"
+ 		echo "Please contact the author at http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/."
+diff --git a/minissdp.c b/minissdp.c
+index f937109..4f7399b 100644
+--- a/minissdp.c
++++ b/minissdp.c
+@@ -32,6 +32,8 @@
+ #define LL_SSDP_MCAST_ADDR "FF02::C"
+ #define SL_SSDP_MCAST_ADDR "FF05::C"
+ 
++char miniupnpd_server_string[MINIUPNPD_SERVER_STRING_LEN];
++
+ /* AddMulticastMembership()
+  * param s		socket
+  * param ifaddr	ip v4 address
+@@ -338,7 +340,7 @@ SendSSDPAnnounce2(int s, const struct sockaddr * addr,
+ 		"ST: %.*s%s\r\n"
+ 		"USN: %s::%.*s%s\r\n"
+ 		"EXT:\r\n"
+-		"SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
++		"SERVER: %s \r\n"
+ 		"LOCATION: http://%s:%u" ROOTDESC_PATH "\r\n"
+ 		"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */
+ 		"01-NLS: %u\r\n" /* same as BOOTID. UDA v1.1 */
+@@ -347,6 +349,7 @@ SendSSDPAnnounce2(int s, const struct sockaddr * addr,
+ 		"\r\n",
+ 		st_len, st, suffix,
+ 		uuidvalue, st_len, st, suffix,
++		miniupnpd_server_string,
+ 		host, (unsigned int)port,
+ 		upnp_bootid, upnp_bootid, upnp_configid);
+ 	addrlen = (addr->sa_family == AF_INET6)
+@@ -435,7 +438,7 @@ SendSSDPNotifies(int s, const char * host, unsigned short port,
+ 			"HOST: %s:%d\r\n"
+ 			"CACHE-CONTROL: max-age=%u\r\n"
+ 			"lOCATION: http://%s:%d" ROOTDESC_PATH"\r\n"
+-			"SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
++			"SERVER: %s\r\n"
+ 			"NT: %s%s\r\n"
+ 			"USN: %s::%s%s\r\n"
+ 			"NTS: ssdp:alive\r\n"
+@@ -448,6 +451,7 @@ SendSSDPNotifies(int s, const char * host, unsigned short port,
+ 			SSDP_PORT,
+ 			lifetime,
+ 			host, port,
++			miniupnpd_server_string,
+ 			known_service_types[i].s, ver_str,
+ 			uuidvalue, known_service_types[i].s, ver_str,
+ 			upnp_bootid, upnp_bootid, upnp_configid );
+@@ -827,9 +831,9 @@ SubmitServicesToMiniSSDPD(const char * host, unsigned short port) {
+ 		CODELENGTH(l, p);
+ 		memcpy(p, strbuf, l);
+ 		p += l;
+-		l = (int)strlen(MINIUPNPD_SERVER_STRING);
++		l = (int)strlen(miniupnpd_server_string);
+ 		CODELENGTH(l, p);
+-		memcpy(p, MINIUPNPD_SERVER_STRING, l);
++		memcpy(p, miniupnpd_server_string, l);
+ 		p += l;
+ 		l = snprintf(strbuf, sizeof(strbuf), "http://%s:%u" ROOTDESC_PATH,
+ 		             host, (unsigned int)port);
+diff --git a/minissdp.h b/minissdp.h
+index 6a41e42..4855bbe 100644
+--- a/minissdp.h
++++ b/minissdp.h
+@@ -9,6 +9,9 @@
+ 
+ #include "miniupnpdtypes.h"
+ 
++extern char miniupnpd_server_string[];
++#define MINIUPNPD_SERVER_STRING_LEN 256
++
+ int
+ OpenAndConfSSDPReceiveSocket(int ipv6);
+ 
+diff --git a/miniupnpd.c b/miniupnpd.c
+index 050d8db..04cb436 100644
+--- a/miniupnpd.c
++++ b/miniupnpd.c
+@@ -1070,6 +1070,13 @@ init(int argc, char * * argv, struct runtime_vars * v)
+ 		case 'f':
+ 			i++;	/* discarding, the config file is already read */
+ 			break;
++		case 'V':
++			if(i+1 < argc) {
++				snprintf(miniupnpd_server_string, MINIUPNPD_SERVER_STRING_LEN,
++				         "%s", argv[++i]);
++			} else
++				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
++			break;
+ 		default:
+ 			fprintf(stderr, "Unknown option: %s\n", argv[i]);
+ 		}
+@@ -1288,6 +1295,8 @@ main(int argc, char * * argv)
+ 	unsigned int next_pinhole_ts;
+ #endif
+ 
++	snprintf(miniupnpd_server_string, MINIUPNPD_SERVER_STRING_LEN,
++	         "%s", MINIUPNPD_SERVER_STRING);
+ 	if(init(argc, argv, &v) != 0)
+ 		return 1;
+ 	/* count lan addrs */
+diff --git a/upnphttp.c b/upnphttp.c
+index 6620bfd..321ac06 100644
+--- a/upnphttp.c
++++ b/upnphttp.c
+@@ -25,6 +25,7 @@
+ #include "upnphttp.h"
+ #include "upnpdescgen.h"
+ #include "miniupnpdpath.h"
++#include "minissdp.h"
+ #include "upnpsoap.h"
+ #include "upnpevents.h"
+ #include "upnputils.h"
+@@ -772,7 +773,7 @@ static const char httpresphead[] =
+ 	"Content-Type: %s\r\n"
+ 	"Connection: close\r\n"
+ 	"Content-Length: %d\r\n"
+-	"Server: " MINIUPNPD_SERVER_STRING "\r\n"
++	"Server: %s\r\n"
+ 	;	/*"\r\n";*/
+ /*
+ 		"<?xml version=\"1.0\"?>\n"
+@@ -791,12 +792,10 @@ BuildHeader_upnphttp(struct upnphttp * h, int respcode,
+                      const char * respmsg,
+                      int bodylen)
+ {
+-	int templen;
+-	if(!h->res_buf ||
+-	   h->res_buf_alloclen < ((int)sizeof(httpresphead) + 256 + bodylen)) {
++	int templen = sizeof(httpresphead) + 256 + bodylen + MINIUPNPD_SERVER_STRING_LEN;
++	if(!h->res_buf || h->res_buf_alloclen < templen) {
+ 		if(h->res_buf)
+ 			free(h->res_buf);
+-		templen = sizeof(httpresphead) + 256 + bodylen;
+ 		h->res_buf = (char *)malloc(templen);
+ 		if(!h->res_buf) {
+ 			syslog(LOG_ERR, "malloc error in BuildHeader_upnphttp()");
+@@ -809,7 +808,7 @@ BuildHeader_upnphttp(struct upnphttp * h, int respcode,
+ 	                         httpresphead, h->HttpVer,
+ 	                         respcode, respmsg,
+ 	                         (h->respflags&FLAG_HTML)?"text/html":"text/xml; charset=\"utf-8\"",
+-							 bodylen);
++							 bodylen, miniupnpd_server_string);
+ 	/* Content-Type MUST be 'text/xml; charset="utf-8"' according to UDA v1.1 */
+ 	/* Content-Type MUST be 'text/xml' according to UDA v1.0 */
+ 	/* Additional headers */
+-- 
+2.1.0.rc2.206.gedb03e5
+
diff --git a/package/miniupnpd/miniupnpd-002-no-console-syslog.patch b/package/miniupnpd/miniupnpd-002-no-console-syslog.patch
new file mode 100644
index 0000000..a1c6951
--- /dev/null
+++ b/package/miniupnpd/miniupnpd-002-no-console-syslog.patch
@@ -0,0 +1,12 @@
+diff -Naur miniupnpd-1.8/miniupnpd.c miniupnpd-1.8.new/miniupnpd.c
+--- miniupnpd-1.8/miniupnpd.c	2014-09-05 14:56:15.664838459 +0000
++++ miniupnpd-1.8.new/miniupnpd.c	2014-09-05 14:51:37.671933829 +0000
+@@ -1103,7 +1103,7 @@
+ #endif
+ 	}
+ 
+-	openlog_option = LOG_PID|LOG_CONS;
++	openlog_option = LOG_PID;
+ 	if(debug_flag)
+ 	{
+ 		openlog_option |= LOG_PERROR;	/* also log on stderr */
diff --git a/package/miniupnpd/miniupnpd.mk b/package/miniupnpd/miniupnpd.mk
index a16d40a..d301df5 100644
--- a/package/miniupnpd/miniupnpd.mk
+++ b/package/miniupnpd/miniupnpd.mk
@@ -14,7 +14,8 @@
 	ARCH=$(BR2_ARCH) \
 	VPATH=$(TARGET_DIR)/usr/lib \
 	PREFIX=$(TARGET_DIR) \
-	IPTABLESPATH=$(IPTABLES_DIR)
+	IPTABLESPATH=$(IPTABLES_DIR) \
+	OS_NAME="Google Fiber"
 
 define MINIUPNPD_BUILD_CMDS
 	$(MAKE1) -f Makefile.linux $(MINIUPNPD_ENV) -C $(@D) all
diff --git a/package/openssh/openssh.mk b/package/openssh/openssh.mk
index 08bb499..7a0fb3f 100644
--- a/package/openssh/openssh.mk
+++ b/package/openssh/openssh.mk
@@ -12,10 +12,23 @@
 
 OPENSSH_DEPENDENCIES = zlib openssl
 
-define OPENSSH_INSTALL_INITSCRIPT
-	$(INSTALL) -D -m 755 package/openssh/S50sshd $(TARGET_DIR)/etc/init.d/S50sshd
+define OPENSSH_INSTALL_TARGET_CMDS
+	$(INSTALL) -m 755 $(@D)/sftp-server $(TARGET_DIR)/usr/libexec/sftp-server
 endef
 
+# @note We are replacing the default install steps
+# with an explicit "install only sftp-server" command.
+# The rationale is that we need sftp-server in order
+# to make sshfs work, but we do not want to move from
+# dropbear to openssh (yet). Once we move, we should
+# remove the explicit install command, so that the
+# whole package gets installed.
+
+define OPENSSH_UNINSTALL_TARGET_CMDS
+	rm -f $(TARGET_DIR)/usr/libexec/sftp-server
+endef
+
+
 OPENSSH_POST_INSTALL_TARGET_HOOKS += OPENSSH_INSTALL_INITSCRIPT
 
 $(eval $(call AUTOTARGETS))
diff --git a/package/python-pypcap/Config.in b/package/python-pypcap/Config.in
new file mode 100644
index 0000000..a1ec7de
--- /dev/null
+++ b/package/python-pypcap/Config.in
@@ -0,0 +1,9 @@
+config BR2_PACKAGE_PYTHON_PYPCAP
+	bool "python-pypcap"
+	depends on BR2_PACKAGE_PYTHON
+	select BR2_PACKAGE_LIBPCAP
+	help
+	  The pypcap module is a object-oriented wrapper of the C libpcap library.
+
+	  https://code.google.com/p/pypcap/
+
diff --git a/package/python-pypcap/python-pypcap.mk b/package/python-pypcap/python-pypcap.mk
new file mode 100644
index 0000000..1bfd724
--- /dev/null
+++ b/package/python-pypcap/python-pypcap.mk
@@ -0,0 +1,42 @@
+################################################################################
+#
+# python-pypcap
+#
+################################################################################
+
+PYTHON_PYPCAP_VERSION = 102
+PYTHON_PYPCAP_SITE = https://pypcap.googlecode.com/svn/trunk
+PYTHON_PYPCAP_SITE_METHOD = svn
+PYTHON_PYPCAP_LICENSE = BSD-3c
+PYTHON_PYPCAP_LICENSE_FILES = LICENSE
+PYTHON_PYPCAP_SETUP_TYPE = distutils
+PYTHON_PYPCAP_DEPENDENCIES = host-python-pyrex libpcap
+
+define PYTHON_PYPCAP_CONFIGURE_CMDS
+	$(HOST_DIR)/usr/bin/pyrexc $(@D)/pcap.pyx
+	(cd $(@D); \
+		$(HOST_DIR)/usr/bin/python setup.py \
+		config --with-pcap=$(STAGING_DIR)/usr)
+endef
+
+define PYTHON_PYPCAP_BUILD_CMDS
+	(cd $(@D); \
+		CC="$(TARGET_CC)"		\
+		CFLAGS="$(TARGET_CFLAGS)" 	\
+		LDSHARED="$(TARGET_CC) -shared" \
+		LDFLAGS="$(TARGET_LDFLAGS) -lpcap" 	\
+	$(HOST_DIR)/usr/bin/python setup.py build_ext \
+	--include-dirs=$(STAGING_DIR)/usr/include/python$(PYTHON_VERSION_MAJOR))
+	(cd $(@D); \
+		CC="$(TARGET_CC)"		\
+		CFLAGS="$(TARGET_CFLAGS)" 	\
+		LDSHARED="$(TARGET_CC) -shared" \
+		LDFLAGS="$(TARGET_LDFLAGS)" 	\
+	$(HOST_DIR)/usr/bin/python setup.py build)
+endef
+
+define PYTHON_PYPCAP_INSTALL_TARGET_CMDS
+	cp $(@D)/build/lib.*/pcap.so $(TARGET_DIR)/usr/lib/python2.7/site-packages/
+endef
+
+$(eval $(call GENTARGETS))
diff --git a/package/python-pyrex/Config.in.host b/package/python-pyrex/Config.in.host
new file mode 100644
index 0000000..d0eefc9
--- /dev/null
+++ b/package/python-pyrex/Config.in.host
@@ -0,0 +1,7 @@
+config BR2_PACKAGE_HOST_PYTHON_PYREX 
+	bool "python-pyrex (host tool)" 
+	depends on BR2_PACKAGE_PYTHON 
+	help 
+	 Pyrex is a language for writing Python extension modules 
+ 
+	 http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/
diff --git a/package/python-pyrex/python-pyrex.mk b/package/python-pyrex/python-pyrex.mk
new file mode 100644
index 0000000..745d25c
--- /dev/null
+++ b/package/python-pyrex/python-pyrex.mk
@@ -0,0 +1,23 @@
+################################################################################
+#
+# python-pyrex
+#
+################################################################################
+
+PYTHON_PYREX_VERSION = 0.9.9
+PYTHON_PYREX_SOURCE = Pyrex-$(PYTHON_PYREX_VERSION).tar.gz
+PYTHON_PYREX_SITE = http://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/
+PYTHON_PYREX_DEPENDENCIES = host-python
+PYTHON_PYREX_LICENSE = Apache-v2
+PYTHON_PYREX_LICENSE_FILES = LICENSE.txt
+PYTHON_PYREX_SETUP_TYPE = distutils
+
+define HOST_PYTHON_PYREX_BUILD_CMDS
+	(cd $(@D); $(HOST_DIR)/usr/bin/python setup.py build)
+endef
+
+define HOST_PYTHON_PYREX_INSTALL_CMDS
+	(cd $(@D); $(HOST_DIR)/usr/bin/python setup.py install --prefix=$(HOST_DIR)/usr)
+endef
+
+$(eval $(call GENTARGETS,host))
diff --git a/package/rsync/rsync.mk b/package/rsync/rsync.mk
index 12a33c6..1cec6e5 100644
--- a/package/rsync/rsync.mk
+++ b/package/rsync/rsync.mk
@@ -8,6 +8,6 @@
 RSYNC_SOURCE = rsync-$(RSYNC_VERSION).tar.gz
 RSYNC_SITE = http://rsync.samba.org/ftp/rsync/src
 RSYNC_CONF_OPT = $(if $(BR2_ENABLE_DEBUG),--enable-debug,--disable-debug)
-RSYNC_CONF_OPT = --with-included-popt
+RSYNC_CONF_OPT = --with-included-popt --disable-acl-support
 
 $(eval $(call AUTOTARGETS))
diff --git a/package/sshfs/Config.in b/package/sshfs/Config.in
index 73d552f..38bf471 100644
--- a/package/sshfs/Config.in
+++ b/package/sshfs/Config.in
@@ -5,7 +5,10 @@
 	select BR2_PACKAGE_GETTEXT if BR2_NEEDS_GETTEXT_IF_LOCALE
 	select BR2_PACKAGE_LIBINTL if BR2_NEEDS_GETTEXT_IF_LOCALE
 	select BR2_PACKAGE_LIBICONV if !BR2_ENABLE_LOCALE
+	# requires sftp-server
 	select BR2_PACKAGE_OPENSSH
+	# requires libfuse
+	select BR2_PACKAGE_LIBFUSE
 	depends on BR2_LARGEFILE
 	depends on BR2_USE_WCHAR # glib2
 	help
diff --git a/package/toybox/toybox.config b/package/toybox/toybox.config
index 2373918..3169aca 100644
--- a/package/toybox/toybox.config
+++ b/package/toybox/toybox.config
@@ -63,7 +63,7 @@
 CONFIG_SWAPON=y
 # CONFIG_SWITCH_ROOT is not set
 # CONFIG_TAC is not set
-# CONFIG_TASKSET is not set
+CONFIG_TASKSET=y
 # CONFIG_TIMEOUT is not set
 CONFIG_TRUNCATE=y
 # CONFIG_UNSHARE is not set