diff --git a/Makefile b/Makefile
index ac52fb0057a2746b1514d8f23661844368169d1b..def5899b7c50a71c2754d9c9e81c6652e9edce30 100644
--- a/Makefile
+++ b/Makefile
@@ -57,6 +57,9 @@ image/$(1): FORCE
 	+@$$(GLUONMAKE) $$@
 endef
 
+define GluonProfileFactorySuffix
+endef
+
 define GluonModel
 endef
 
@@ -127,12 +130,17 @@ define GluonProfile
 PROFILES += $(1)
 PROFILE_PACKAGES += $(filter-out -%,$(2) $(GLUON_$(1)_SITE_PACKAGES))
 GLUON_$(1)_DEFAULT_PACKAGES := $(2)
+GLUON_$(1)_FACTORY_SUFFIX := .bin
 GLUON_$(1)_MODELS :=
 endef
 
+define GluonProfileFactorySuffix
+GLUON_$(1)_FACTORY_SUFFIX := $(2)
+endef
+
 define GluonModel
-GLUON_$(1)_MODELS += $(2)
-GLUON_$(1)_MODEL_$(2) := $(3)
+GLUON_$(1)_MODELS += $(3)
+GLUON_$(1)_MODEL_$(3) := $(2)
 endef
 
 
@@ -339,11 +347,13 @@ image: FORCE
 		PROFILE="$(PROFILE)" KDIR="$(PROFILE_KDIR)" TARGET_DIR="$(TARGET_DIR)" BIN_DIR="$(BIN_DIR)" TMP_DIR="$(TMP_DIR)"
 
 	$(foreach model,$(GLUON_$(PROFILE)_MODELS), \
-		rm -f $(GLUON_IMAGEDIR)/factory/gluon-*-$(GLUON_$(PROFILE)_MODEL_$(model)).bin && \
-		rm -f $(GLUON_IMAGEDIR)/sysupgrade/gluon-*-$(GLUON_$(PROFILE)_MODEL_$(model))-sysupgrade.bin && \
+		rm -f $(GLUON_IMAGEDIR)/sysupgrade/gluon-*-$(model)-sysupgrade.bin && \
+		cp $(BIN_DIR)/gluon-$(GLUON_$(PROFILE)_MODEL_$(model))-sysupgrade.bin $(GLUON_IMAGEDIR)/sysupgrade/$(IMAGE_PREFIX)-$(model)-sysupgrade.bin && \
 		\
-		cp $(BIN_DIR)/gluon-$(model)-factory.bin $(GLUON_IMAGEDIR)/factory/$(IMAGE_PREFIX)-$(GLUON_$(PROFILE)_MODEL_$(model)).bin && \
-		cp $(BIN_DIR)/gluon-$(model)-sysupgrade.bin $(GLUON_IMAGEDIR)/sysupgrade/$(IMAGE_PREFIX)-$(GLUON_$(PROFILE)_MODEL_$(model))-sysupgrade.bin && \
+		$(if $(GLUON_$(PROFILE)_FACTORY_SUFFIX), \
+			rm -f $(GLUON_IMAGEDIR)/factory/gluon-*-$(model)$(GLUON_$(PROFILE)_FACTORY_SUFFIX) && \
+			cp $(BIN_DIR)/gluon-$(GLUON_$(PROFILE)_MODEL_$(model))-factory$(GLUON_$(PROFILE)_FACTORY_SUFFIX) $(GLUON_IMAGEDIR)/factory/$(IMAGE_PREFIX)-$(model)$(GLUON_$(PROFILE)_FACTORY_SUFFIX) && \
+		) \
 	) :
 
 image/%: $(gluon_prepared_stamp)
@@ -363,10 +373,10 @@ manifest: FORCE
 		echo && \
 		($(foreach profile,$(PROFILES), \
 			$(foreach model,$(GLUON_$(profile)_MODELS), \
-				for file in gluon-*-'$(GLUON_$(profile)_MODEL_$(model))-sysupgrade.bin'; do \
+				for file in gluon-*-'$(model)-sysupgrade.bin'; do \
 					[ -e "$$file" ] && echo \
-						'$(GLUON_$(profile)_MODEL_$(model))' \
-						"$$(echo "$$file" | sed -n -r -e 's/^gluon-$(call regex-escape,$(GLUON_SITE_CODE))-(.*)-$(call regex-escape,$(GLUON_$(profile)_MODEL_$(model)))-sysupgrade\.bin$$/\1/p')" \
+						'$(model)' \
+						"$$(echo "$$file" | sed -n -r -e 's/^gluon-$(call regex-escape,$(GLUON_SITE_CODE))-(.*)-$(call regex-escape,$(model))-sysupgrade\.bin$$/\1/p')" \
 						"$$($(SHA512SUM) "$$file")" \
 						"$$file" && break; \
 				done; \
diff --git a/contrib/sign.sh b/contrib/sign.sh
index 383600cb3ad658fdc7d2a6b34d56e75706b33c6a..a88c52df7a264ecc1399e72f0c7fb61d266e8b12 100755
--- a/contrib/sign.sh
+++ b/contrib/sign.sh
@@ -3,6 +3,18 @@
 if [ $# -eq 0 -o "-h" = "$1" -o "-help" = "$1" -o "--help" = "$1" ]; then
 	cat <<EOHELP
 Usage: $0 <secret> <manifest>
+
+sign.sh adds lines to a manifest to indicate the approval
+of the integrity of the firmware as required for automated
+updates. The first argument <secret> references a file harboring
+the private key of a public-private key pair of a developer
+that referenced by its public key in the site configuration.
+The script may be performed multiple times to the same document
+to indicate an approval by multiple developers.
+
+See also
+ * edcsautils on https://github.com/tcatm/ecdsautils
+
 EOHELP
 	exit 1
 fi
diff --git a/docs/dev/configmode.rst b/docs/dev/configmode.rst
new file mode 100644
index 0000000000000000000000000000000000000000..9a174d4c4a49824c2a09f7bbe86d7157c37368b0
--- /dev/null
+++ b/docs/dev/configmode.rst
@@ -0,0 +1,92 @@
+Config Mode
+===========
+
+As of 2014.4 `gluon-config-mode` consists of several modules.
+
+gluon-config-mode-core
+    This modules provides the core functionality for the config mode.
+    All modules must depend on it.
+
+gluon-config-mode-hostname
+    Provides a hostname field.
+
+gluon-config-mode-autoupdater
+    Informs whether the autoupdater is enabled.
+
+gluon-config-mode-mesh-vpn
+    Allows toggling of mesh-vpn-fastd and setting a bandwidth limit.
+
+gluon-config-mode-geo-location
+    Enables the user to set the geographical location of the node.
+
+gluon-config-mode-contact-info
+    Adds a field where the user can provide contact information.
+
+In order to get a config mode close to the one found in 2014.3.x you may add
+these modules to your `site.mk`:
+gluon-config-mode-hostname,
+gluon-config-mode-autoupdater,
+gluon-config-mode-mesh-vpn,
+gluon-config-mode-geo-location,
+gluon-config-mode-contact-info
+
+Writing Config Mode Modules
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Config mode modules are located at `/lib/gluon/config-mode/wizard` and
+`/lib/gluon/config-mode/reboot`. Modules are named like `0000-name.lua` and
+are executed in lexical order. If you take the standard set of modules, the
+order is, for wizard modules:
+
+  - 0050-autoupdater-info
+  - 0100-hostname
+  - 0300-mesh-vpn
+  - 0400-geo-location
+  - 0500-contact-info
+
+While for reboot modules it is:
+
+  - 0100-mesh-vpn
+  - 0900-msg-reboot
+
+Wizards
+-------
+
+Wizard modules return a UCI section. A simple module capable of changing the
+hostname might look like this::
+
+  local cbi = require "luci.cbi"
+  local uci = luci.model.uci.cursor()
+
+  local M = {}
+
+  function M.section(form)
+    local s = form:section(cbi.SimpleSection, nil, nil)
+    local o = s:option(cbi.Value, "_hostname", "Hostname")
+    o.value = uci:get_first("system", "system", "hostname")
+    o.rmempty = false
+    o.datatype = "hostname"
+  end
+
+  function M.handle(data)
+    uci:set("system", uci:get_first("system", "system"), "hostname", data._hostname)
+    uci:save("system")
+    uci:commit("system")
+  end
+
+  return M
+
+Reboot page
+-----------
+
+Reboot modules return a function that will be called when the page is to be
+rendered or nil (i.e. the module is skipped)::
+
+  if no_hello_world_today then
+    return nil
+  else
+    return function ()
+      luci.template.render_string("Hello World!")
+    end
+  end
+
diff --git a/docs/dev/hardware.rst b/docs/dev/hardware.rst
index 694a8cd93e83377afe2347379b9be0325e998429..bf033280960a0b66508b92c0ef59ece053cfe8a9 100644
--- a/docs/dev/hardware.rst
+++ b/docs/dev/hardware.rst
@@ -45,7 +45,7 @@ The final image name must be the same that is returned by the following command.
     lua -e 'print(require("platform_info").get_image_name())'
 
 
-This is so the autoupdater can work. On targets which aren't supported by the autoupdater,
+This is just so the autoupdater can work. The command has to be executed _on_ the target (eg. the hardware router with a flashed image). So you'll first have to build an image with a guessed name, and afterwards build a new, correctly named image. On targets which aren't supported by the autoupdater,
 ``require("platform_info").get_image_name()`` will just return ``nil`` and the final image name
 may be defined arbitrarily.
 
diff --git a/docs/index.rst b/docs/index.rst
index 7a1d5c746700b92144578c3479818bc124f2bcd9..9ca1862c61a8a35b7a79e0d5e51b4d3344556838 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -36,26 +36,49 @@ Developer Documentation
 
    dev/basics
    dev/hardware
+   dev/configmode
 
 Supported Devices
 -----------------
 
+* Buffalo
+
+  - WZR-HP-AG300H / WZR-600DHP
+  - WZR-HP-G450H
+
+* D-Link
+
+  - DIR-825 (B1)
+
+* Linksys
+
+  - WRT160NL
+
 * TP-Link
 
+  - CPE210 (v1)
+  - CPE220 (v1)
+  - CPE510 (v1)
+  - CPE520 (v1)
+  - TL-MR3020 (v1)
+  - TL-MR3040 (v1, v2)
+  - TL-MR3220 (v1)
+  - TL-MR3420 (v1, v2)
+  - TL-WA750RE (v1)
+  - TL-WA801N/ND (v2)
+  - TL-WA850RE (v1)
+  - TL-WA901N/ND (v2)
+  - TL-WDR3500 (v1)
+  - TL-WDR3600 (v1)
+  - TL-WDR4300 (v1)
+  - TL-WR1043N/ND (v1, v2)
+  - TL-WR703N (v1)
+  - TL-WR710N (v1)
   - TL-WR740N (v1, v3, v4)
   - TL-WR741N/ND (v1, v2, v4)
   - TL-WR841N/ND (v3, v5, v7, v8, v9)
   - TL-WR842N/ND (v1, v2)
   - TL-WR941N/ND (v2, v3, v4)
-  - TL-WR1043N/ND (v1, v2)
-  - TL-WDR3500 (v1)
-  - TL-WDR3600 (v1)
-  - TL-WDR4300 (v1)
-  - TL-WA901N/ND (v2)
-  - TL-MR3020 (v1)
-  - TL-MR3040 (v1)
-  - TL-MR3220 (v1)
-  - TL-MR3420 (v1, v2)
 
 * Ubiquiti
 
@@ -65,14 +88,6 @@ Supported Devices
   - UniFi AP
   - UniFi AP Outdoor
 
-* D-Link
-
-  - DIR-615 (E1)
-  - DIR-825 (B1)
-
-* Linksys
-
-  - WRT160NL
 
 Releases
 --------
diff --git a/docs/releases/v2014.4.rst b/docs/releases/v2014.4.rst
index 5471d419a73ac326b00206e5e10e1cef0ecdeaba..f05e06a6a8ef5a621a098cef3ebb7307e23acc29 100644
--- a/docs/releases/v2014.4.rst
+++ b/docs/releases/v2014.4.rst
@@ -1,23 +1,98 @@
-Gluon 2014.4 (In development)
-=============================
+Gluon 2014.4
+============
+
+Added (and removed) hardware support
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* Buffalo
+
+  - WZR-HP-AG300H / WZR-600DHP
+  - WZR-HP-G450H
+
+* D-Link
+
+  - DIR-615 (E1) support had to be dropped
+
+* TP-LINK
+
+  - CPE210/220/510/520 (v1)
+  - TL-MR3040 (v2
+  - TL-WA750RE (v1)
+  - TL-WA801N/ND (v2)
+  - TL-WA850RE (v1)
+  - TL-WR703N (v1)
+  - TL-WR710N (v1)
+  - TL-WR1043N/ND (v2)
 
-New hardware support
-~~~~~~~~~~~~~~~~~~~~
-* TP-Link TL-WR1043N/ND v2
 
 New features
 ~~~~~~~~~~~~
+OpenWrt Barrier Breaker
+-----------------------
+Switching to the new OpenWrt release 14.09 ("Barrier Breaker") has yielded
+lots of updates for both the kernel and most packages. Besides better
+performance, this has also greatly improved stability (far less out-of-memory
+issues!).
 
 Modular config mode
 -------------------
+The old ``gluon-config-mode`` package has been split into five
+small packages, each providing a single section of the config
+mode form. This simplifies removing or replacing parts of the wizard.
+
+See the *Site changes* section for details.
+
+Experimental support for batman-adv compat 15
+---------------------------------------------
+As batman-adv has broken compatiblity starting with batman-adv 2014.0
+(bumping the "compat level" to 15), Gluon users must decide which
+batman-adv version to use. The package for the old batman-adv version
+``gluon-mesh-batman-adv`` has been renamed to ``gluon-mesh-batman-adv-14``,
+the new version can be used with ``gluon-mesh-batman-adv-15``.
+
+Please note that batman-adv compat 15 still isn't tested very well
+(and there are known bugs in the current release 2014.3), so for now
+we still recommend using compat 14 in "production" environments.
+
+fastd v16
+---------
+Besides other new features and bugfixes, fastd v16 support the new
+authentication method "UMAC". We recommend switching from the old
+``salsa2012+gmac`` and ``null+salsa2012+gmac`` methods to the new
+``salsa2012+umac`` and ``null+salsa2012+umac`` as UMAC is
+much faster and even more secure than GMAC.
+
+Private WLAN
+------------
+The new package ``gluon-luci-private-wifi`` allows to configure a private WLAN
+with WPA-PSK in the expert mode which is bridged with the WAN uplink.
+
+Embedding SSH keys
+------------------
+
+Using ``gluon-authorized-keys`` it is possible to embed predefined SSH
+public keys to firmware images. If ``gluon-config-mode-*`` is left out
+images will be ready to mesh after the first boot with SSH running for
+further configuration.
+
+Status page resolves nodenames
+------------------------------
+
+The tools ``gluon-announced`` and ``gluon-neighbour-info`` are now
+available. Using them enables the status page to resolve hostnames and
+IPs of a nodes' neighbours.
+
+This will also work on devices with multiple wireless interfaces.
 
 Bugfixes
 ~~~~~~~~
 
+* Expert Mode: Fixed all SSH keys being removed when a password was set
+* ``gluon-mesh-vpn-fastd``: Fixed VPN peers removed from the ``site.conf`` not being removed from ``/etc/config/fastd``
+* TL-LINK TL-WDR3600/4300: Added workaround for reboot issues
+* Improved stability (due to switch to OpenWrt Barrier Breaker)
+
 Site changes
 ~~~~~~~~~~~~
-* ``site.conf``
-
 * ``site.mk``
 
   - Obsolete packages:
@@ -32,8 +107,46 @@ Site changes
     + ``gluon-config-mode-mesh-vpn``
     + ``gluon-config-mode-geo-location``
     + ``gluon-config-mode-contact-info``
-    + ``gluon-mesh-batman-adv-14`` or ``gluon-mesh-batman-adv-15`` (specify this before all other packages in the list)
+    + ``gluon-mesh-batman-adv-14`` (specify this before all other packages in the ``site.mk``!)
 
 Internals
 ~~~~~~~~~
-* We're on Barrier Breaker now!
+The switch to Barrier Breaker has led to a multitude of changes all over Gluon:
+
+* The config mode/setup mode is now started by an own set of init scripts in ``/lib/gluon/setup-mode/rc.d`` run by procd
+* Many tools and services used by Gluon have been replaced by our own implementations to reduce the size of the images:
+
+  - ethtool has been replaced by our minimal Lua library *lua-ethtool-stats*
+  - tc has been replaced by our minimal implementation *gluon-simple-tc*
+  - radvd has been replaced by our minimal implementation *gluon-radvd*
+
+Known Issues
+~~~~~~~~~~~~
+
+Alfred crashes
+--------------
+
+https://github.com/freifunk-gluon/gluon/issues/177
+
+Alfred may still crash unconditionally. Some measures have been taken
+to aid but the core problem hasn't been analyzed yet.
+
+Out of memory / batman-adv memory leaks
+---------------------------------------
+
+https://github.com/freifunk-gluon/gluon/issues/216
+
+In some (hopefully rare!) cases batman-adv may still leak memory
+associated with global TT entries. This may result in kernel panics or
+out-of-memory conditions.
+
+
+Ignored tx-power offset on Ubiquiti AirMax devices
+--------------------------------------------------
+
+https://github.com/freifunk-gluon/gluon/issues/94
+
+There is still no OpenWRT support for determining the transmission
+power offsets on Ubiquiti AirMax devices (Bullet M2, Picostation
+M2, Nanostation (loco) M2, ...). Use Gluon with caution on these
+devices! Manual adjustment may be required.
diff --git a/docs/site-example/modules b/docs/site-example/modules
index 2bfc37314663d382cbc201ea0305a977b8d07764..05856ce40f8f5723142be765fa13246b7163a932 100644
--- a/docs/site-example/modules
+++ b/docs/site-example/modules
@@ -1,28 +1,22 @@
-##	gluon site modules example
-#		this file allows to define additional
-#		package feeds to be used.
-#		packages from this feeds can then be included
-#		via site.mk
-
-
-##	GLUON_SITE_FEEDS
-#		feeds to include, note that this is not called
-#		GLUON_FEEDS as in the Gluon modules file.
+# This file allows specifying additional repositories to use
+# when building gluon.
 #
-#		for each feed name given, there have to be
-#		two variables given in the following.
-
-GLUON_SITE_FEEDS='ffhh_packages'
+# In most cases, it is not required so don't add it.
 
+##	GLUON_SITE_FEEDS
+#		for each feed name given, add the corresponding PACKAGES_* lines
+#		documented below
+#GLUON_SITE_FEEDS='my_own_packages'
 
 ##	PACKAGES_$feedname_REPO
 #		the  git repository from where to clone the package feed
-
-PACKAGES_FFHH_PACKAGES_REPO=git://github.com/freifunkhamburg/ffhh-packages.git
+#PACKAGES_MY_OWN_PACKAGES_REPO=https://github.com/.../my-own-packages.git
 
 
 ##	PACKAGES_$feedname_COMMIT
 #		the version/commit of the git repository to clone
+#PACKAGES_MY_OWN_PACKAGES_COMMIT=123456789aabcda1a69b04278e4d38f2a3f57e49
 
-PACKAGES_FFHH_PACKAGES_COMMIT=0fc9d44e95000c61a69b04278e4d38f2a3f57e49
-
+##  PACKAGES_$feedname_BRANCH
+#   the branch to check out
+#PACKAGES_MY_OWN_PACKAGES_BRANCH=my_branch
diff --git a/docs/site-example/site.conf b/docs/site-example/site.conf
index 12607a559520507c7e56e8e640d9529d344d8b69..c4e7f8ad95e294d6b40076b82ab80b8522f0afb3 100644
--- a/docs/site-example/site.conf
+++ b/docs/site-example/site.conf
@@ -1,236 +1,169 @@
---[[	gluon site.conf example
-
-		This file is loosely related to the original site.conf used in Lübeck.
-		There are comments added to most switches to explain the usage of gluon.
-
-	This is lua code now, not perl anymore.
-
-	Happy compiling!
-]]
-
+-- This is an example site configuration for Gluon v2014.4
+--
+-- Take a look at the documentation located at
+-- http://gluon.readthedocs.org/ for details.
+--
+-- This configuration will not work as it. You're required to make
+-- community specific changes to it!
 {
-	--[[	Community settings
-	hostname_prefix:	Nodename prefix
-		freifunk-abcdef123456 (hex-part is generated from node's MAC address)
-	site_name:			Name of your community
-	site_code:			Shortcode of your community
-	]]
-	hostname_prefix = 'freifunk',
-	site_name = 'Freifunk Lübeck',
-	site_code = 'ffhl',
-
-
-	--[[	General network settings
-	prefix4:			IPv4 range of your community
-	prefix6:			IPv6 range of your community
-		is also required for radvd
-	]]
-	prefix4 = '10.130.0.0/20',
-	prefix6 = 'fdef:ffc0:3dd7::/64',
-
-
-	--[[	NTP settings
-			Synchronize the time of the nodes
-	timezone:			Timezone of your community
-		http://wiki.openwrt.org/doc/uci/system#time.zones
-	ntp_servers:		List of NTP-Servers to query. You can use any public and/or your private NTP-Servers of your community.
-		http://www.pool.ntp.org/zone/de
-	 ]]
-	timezone = 'CET-1CEST,M3.5.0,M10.5.0/3',
-	ntp_servers = {'1.ntp.services.ffhl'},
-
-
-	--[[	Wireless settings
-	regdom:			IEEE 802.11 Regulatory Domain
-		http://en.wikipedia.org/wiki/IEEE_802.11#Regulatory_domains_and_legal_compliance
-	wifi24:			Wifi settings for 2.4 GHz frequency devices
-	wifi5:			Wifi settings for 5 GHz frequency devices
-		sub
-	ssid:			Wifi name shown to the user (We recommend %site_code%.freifunk.net)
-	channel:		Wifi channel to use
-	htmode:			Specifies the channel width in 802.11n and 802.11ac mode, possible values are:
-						HT20 (single 20MHz channel),
-						HT40- (2x 20MHz channels, primary/control channel is upper, secondary channel is below)
-						HT40+ (2x 20MHz channels, primary/control channel is lower, secondary channel is above).
-						VHT20 / VHT40 / VHT80 / VHT160 (channel width in 802.11ac, extra channels are picked according to the specification)
-		http://wiki.openwrt.org/doc/uci/wireless#common.options (-> htmode)
-	mesh_ssid:		SSID of the mesh-interface, only used between nodes
-	mesh_bssid:		BSSID of the mesh-interface
-	                        The supplied default of ff:ff:ff:ff:ff:ff will not work.
-	                        You'll need to replace it with randomly generated, non-broadcast BSSID!
-	mesh_mcast_rate:	multicast rate of the mesh-interface
-	]]
-	regdom = 'DE',
-
-	wifi24 = {
-		ssid = 'luebeck.freifunk.net',
-		channel = 1,
-		htmode = 'HT40+',
-		mesh_ssid = 'ff:ff:ff:ff:ff:ff',
-		mesh_bssid = 'ff:ff:ff:ff:ff:ff',
-		mesh_mcast_rate = 12000,
-	},
-
-	wifi5 = {
-		ssid = 'luebeck.freifunk.net',
-		channel = 44,
-		htmode = 'HT40+',
-		mesh_ssid = 'ff:ff:ff:ff:ff:ff',
-		mesh_bssid = 'ff:ff:ff:ff:ff:ff',
-		mesh_mcast_rate = 12000,
-	},
-
-
-	--[[	Next-Node
-	next_node:		Howto reach the node you are currently connected to
-			The node will always be reachable at that address, and it's the same on all nodes. Because next_node packets are redirected within the node itself, there will be no conflicts.
-		sub
-	ip4:			IPv4 Address to use
-	ip6:			IPv6 Address to use
-	mac:			MAC Address to use
-		(TODO: What is the purpose of this MAC-Address here?)
-	]]
-	next_node = {
-		ip4 = '10.130.0.1',
-		ip6 = 'fdef:ffc0:3dd7::1',
-		mac = '16:41:95:40:f7:dc',
-	},
-
-
-	--[[	Gateway settings
-	fastd_mesh_vpn:	fastd vpn settings
-		https://projects.universe-factory.net/projects/fastd/wiki/User_manual
-		sub
-	methods:		encryption algorithms to use
-		https://projects.universe-factory.net/projects/fastd/wiki/Methods
-		When multiple method statements are given, the first one has the highest preference.
-	mtu:			package size
-	backbone:		fastd vpn gateways of your community
-		sub
-	limit:			Number of gateways each node connects to
-		On startup, each node tries to connect to every gateway, and then chooses the number of 'limit' fastest gateways it could reach
-	peers:			Gateways
-		sub sub
-	key:			public fastd key of your gateway
-		https://github.com/tcatm/ecdsautils
-	remotes:		List of fastd configuration strings to connect to your gateway server
-	]]
-	fastd_mesh_vpn = {
-		methods = {'salsa2012+gmac'},
-		mtu = 1426,
-		backbone = {
-			limit = 2,
-			peers = {
-				burgtor = {
-					key = '657af03e36ff1b8bbe5a5134982a4f110c8523a9a63293870caf548916a95a03',
-					remotes = {'ipv4 "burgtor.mesh.ffhl.chaotikum.org" port 10000'},
-				},
-				holstentor = {
-					key = '8c660f7511bf101ea1b599fe53af20e1146cd923c9e9d2a3a0d534ee75af9067',
-					remotes = {'ipv4 "holstentor.mesh.ffhl.chaotikum.org" port 10000'},
-				},
-				huextertor = {
-					key = 'a1b124f43eae4f5929850c09cda825ef35d659e3db4d7746e3d97627e9fa7238',
-					remotes = {'ipv4 "huextertor.mesh.ffhl.chaotikum.org" port 10000'},
-				},
-				muehlentor = {
-					key = 'bd4ec3cf87bb0042eed2fa121fbc402154d28fb1ae9dff9cdb71bb21892f401a',
-					remotes = {'ipv4 "muehlentor.mesh.ffhl.chaotikum.org" port 10000'},
-				},
-			},
-		},
-	},
-
-
-	--[[	Autoupdater settings
-	branch:			Automatically update to this branch
-	branches:		Available branches your community is publishing
-		sub sub
-	name:			Name of branch (is used when compiling images)
-	mirrors:		List of urls where to find the firmware
-		just serve the images on port 80 via http. a simple apache file-listing is enough.
-		see: http://luebeck.freifunk.net/firmware/
-	probability:	How often should a node search for updates
-		1.0 - perform an update every hour
-		0.5 - on average, perform an update every two hours
-		0.0 - inhibit any automatic updates
-	good_signatures:	How many signatures should be valid so the node decides to upgrade itself
-	pubkeys:		public keys by developers used in manifest file of branch
-		manifest file - see gluon readme
-		$ make manifest GLUON_BRANCH=mybranch
-		$ contrib/sign.sh $SECRETKEY.file images/sysupgrade/manifest
-	]]
-	autoupdater = {
-		branch = 'experimental',
-		branches = {
-			stable = {
-				name = 'stable',
-				mirrors = {'http://1.updates.services.ffhl/stable/sysupgrade'},
-				probability = 0.08,
-				good_signatures = 2,
-				pubkeys = {
-					'daa19b44bbd7033965e02088127bad9516ba0fea8f34267a777144a23ec8900c', -- Linus
-					'a8dd60765b07330a4bbfdf8406102befca132881a4b65f3efda32cf2d5b362d9', -- Nils
-					'323bd3285c4e5547a89cd6da1f2aef67f1654b0928bbd5b104efc9dab2156d0b', -- NeoRaider
-				},
-			},
-			experimental = {
-				-- DE: Name des "braches" wird beim erstellen von Images / update generiert
-				name = 'experimental',
-				mirrors = {'http://1.updates.services.ffhl/experimental/sysupgrade'},
-				probability = 1.00,
-				good_signatures = 2,
-				good_signatures = 1,
-				-- DE: Oeffentlicher Schluessel / Public Key der Entwickler
-				pubkeys = {
-					'496136b37e5f561dfdf523611f14e4b6bc2a745cbc1ab7daffa59fded5f202d1', -- philae
-				},
-			},
-		},
-	},
-
-
-	--[[	Simple TC settings to limit the bandwidth of the vpn-uplink
-	mesh_vpn:
-		sub
-	ifname:		name of the interface/bridge
-	enabled:	default-value
-	limit_egress:	default-value
-	limit_ingress:	default-value
-	]]
-	simple_tc = {
-		mesh_vpn = {
-			ifname = 'mesh-vpn',
-			enabled = false,
-			limit_egress = 200,
-			limit_ingress = 3000,
-		},
-	},
-
-
-	--[[	Config Mode settings
-		Text shown on local website on node while in config mode (after initial flashing or after a long press and hold on the primary button and reboot). You can use html here.
-	msg_welcome:		Welcome message shown at startup
-	msg_pubkey:		Instructions for the user how your community handles the key exchange
-		only shown if VPN setting is selected
-	msg_reboot:		Message shown when configuration is finished while the node is rebooting.
-
-		Variables
-		Within the text given here you can use variables which are
-		replaced when the respective website is delivered to the user.
-		Variables must be used in the format <%=NAME%>. See msg_pubkey for an example.
-	hostname		hostname of the node
-	pubkey			fastd public key of the node
-	sysconfig.primary_mac	the primary mac of the node, also found printed beneath the device
-	... other sysconfig.* variables: config_ifname, lan_ifname, wan_ifname
-	]]
-	config_mode = {
-		msg_welcome = [[
+  -- Used for generated hostnames, e.g. freifunk-abcdef123456.
+  hostname_prefix = 'freifunk',
+
+  -- Name of the community.
+  site_name = 'Freifunk Lübeck',
+
+  -- Shorthand of the community.
+  site_code = 'ffhl',
+
+  -- Prefixes used within the mesh. Both are required.
+  prefix4 = '10.130.0.0/20',
+  prefix6 = 'fdef:ffc0:3dd7::/64',
+
+  -- Timezone of your community.
+  -- See http://wiki.openwrt.org/doc/uci/system#time_zones
+  timezone = 'CET-1CEST,M3.5.0,M10.5.0/3',
+
+  -- List of NTP servers in your community.
+  -- Must be reachable using IPv6!
+  ntp_servers = {'1.ntp.services.ffhl'},
+
+  -- Wireless regulatory domain of your community.
+  regdom = 'DE',
+
+  -- Wireless configuratoin for 2.4 GHz interfaces.
+  wifi24 = {
+    -- Wireless channel.
+    channel = 1,
+
+    -- ESSID used for client network.
+    ssid = 'luebeck.freifunk.net',
+
+    -- Specifies the channel width in 802.11n and 802.11ac mode.
+    -- Possible values are:
+    -- HT20 (single 20MHz channel),
+    -- HT40- (2x 20MHz channels, secondary below)
+    -- HT40+ (2x 20MHz channels, secondary above)
+    htmode = 'HT20',
+
+    -- Adjust these values!
+    mesh_ssid = 'XX:XX:XX:XX:XX:XX',  -- ESSID used for mesh
+    mesh_bssid = 'XX:XX:XX:XX:XX:XX', -- BSSID used for mesh
+
+    -- Bitrate used for multicast/broadcast packets.
+    mesh_mcast_rate = 12000,
+  },
+
+  -- Wireless configuration for 5 GHz interfaces.
+  -- This should be equal to the 2.4 GHz variant, except
+  -- for channel and htmode.
+  wifi5 = {
+    ssid = 'luebeck.freifunk.net',
+    channel = 44,
+    htmode = 'HT20',
+    mesh_ssid = 'XX:XX:XX:XX:XX:XX',
+    mesh_bssid = 'XX:XX:XX:XX:XX:XX',
+    mesh_mcast_rate = 12000,
+  },
+
+  -- The next node feature allows clients to always reach the node it is
+  -- connected to using a known IP address.
+  next_node = {
+    -- anycast IPs of all nodes
+    ip4 = '10.130.0.1',
+    ip6 = 'fdef:ffc0:3dd7::1',
+
+    -- anycast MAC of all nodes
+    mac = '16:41:95:40:f7:dc',
+  },
+
+  -- Refer to http://fastd.readthedocs.org/en/latest/ to better understand
+  -- what these options do.
+  fastd_mesh_vpn = {
+    -- List of crypto-methods to use.
+    methods = {'salsa2012+gmac'},
+    mtu = 1426,
+    backbone = {
+      -- Limit number of connected peers to reduce bandwidth.
+      limit = 2,
+
+      -- List of peers.
+      peers = {
+        burgtor = {
+          key = '657af03e36ff1b8bbe5a5134982a4f110c8523a9a63293870caf548916a95a03',
+
+          -- This is a list, so you might add multiple entries.
+          remotes = {'ipv4 "burgtor.mesh.ffhl.chaotikum.org" port 10000'},
+        },
+        holstentor = {
+          key = '8c660f7511bf101ea1b599fe53af20e1146cd923c9e9d2a3a0d534ee75af9067',
+          remotes = {'ipv4 "holstentor.mesh.ffhl.chaotikum.org" port 10000'},
+        },
+      },
+    },
+  },
+
+  autoupdater = {
+    -- Default branch. Don't forget to set GLUON_BRANCH when building!
+    branch = 'stable',
+
+    -- List of branches. You may define multiple branches.
+    branches = {
+      stable = {
+        name = 'stable',
+
+        -- List of mirrors to fetch images from. IPv6 required!
+        mirrors = {'http://1.updates.services.ffhl/stable/sysupgrade'},
+
+        -- Number of good signatures required.
+        -- Have multiple maintainers sign your build and only
+        -- accept it when a sufficient number of them have
+        -- signed it.
+        good_signatures = 2,
+
+        -- List of public keys of maintainers.
+        pubkeys = {
+                'daa19b44bbd7033965e02088127bad9516ba0fea8f34267a777144a23ec8900c', -- Linus
+                'a8dd60765b07330a4bbfdf8406102befca132881a4b65f3efda32cf2d5b362d9', -- Nils
+                '323bd3285c4e5547a89cd6da1f2aef67f1654b0928bbd5b104efc9dab2156d0b', -- NeoRaider
+        },
+      },
+    },
+  },
+
+  -- Bandwidth limiting
+  simple_tc = {
+    mesh_vpn = {
+      ifname = 'mesh-vpn',
+
+      -- You may enable it by default here.
+      enabled = false,
+
+      -- Default upload limit (kbit/s).
+      limit_egress = 200,
+
+      -- Default download limit (kbit/s).
+      limit_ingress = 3000,
+    },
+  },
+
+  -- These strings are shown in config mode. Some HTML is permissible.
+  --
+  -- msg_welcome: shown at startup
+  -- msg_pubkey:  shown when VPN is enabled
+  -- msg_reboot:  shown during reboot (after finishing configuration)
+  --
+  -- You may use some variables, e.g.:
+  --
+  -- <%=hostname%>               - the node's hostname
+  -- <%=pubkey%>                - the fastd public key
+  -- <%=sysconfig.primary_mac%> - the node's primary MAC
+  config_mode = {
+    msg_welcome = [[
 Willkommen zum Einrichtungsassistenten für deinen neuen Lübecker
 Freifunk-Knoten. Fülle das folgende Formular deinen Vorstellungen
 entsprechend aus und sende es ab.
 ]],
-		msg_pubkey = [[
+    msg_pubkey = [[
 Dies ist der öffentliche Schlüssel deines Freifunk-Knotens. Erst nachdem
 er auf den Servern des Lübecker Freifunk-Projektes eingetragen wurde,
 kann sich dein Knoten mit dem Lübecker Mesh-VPN zu verbinden. Bitte
@@ -238,7 +171,7 @@ schicke dazu diesen Schlüssel und den Namen deines Knotens
 (<em><%=hostname%></em>) an
 <a href="mailto:keys@luebeck.freifunk.net">keys@luebeck.freifunk.net</a>.
 ]],
-		msg_reboot = [[
+    msg_reboot = [[
 <p>
 Dein Knoten startet gerade neu und wird anschließend versuchen,
 sich anschließend mit anderen Freifunk-Knoten in seiner Nähe zu
@@ -250,5 +183,5 @@ Lübecker Freifunk-Community findest du auf
 Viel Spaß mit deinem Knoten und der Erkundung von Freifunk!
 </p>
 ]],
-	},
+  },
 }
diff --git a/docs/site-example/site.mk b/docs/site-example/site.mk
index f7304337f2e5f676847a534846c94d683a04d997..68d14b0e65606c69ea4effb09cbb74541ee27ddc 100644
--- a/docs/site-example/site.mk
+++ b/docs/site-example/site.mk
@@ -5,7 +5,7 @@
 #		The gluon-mesh-batman-adv-* package must come first because of the dependency resolution
 
 GLUON_SITE_PACKAGES := \
-	gluon-mesh-batman-adv-15 \
+	gluon-mesh-batman-adv-14 \
 	gluon-alfred \
 	gluon-announced \
 	gluon-autoupdater \
diff --git a/docs/user/site.rst b/docs/user/site.rst
index 1e9e5986935b4d828fa6ff07c2437d6c4c8551f4..5c8679bbd3d4f932cf8f661d6d7b658a55b2534c 100644
--- a/docs/user/site.rst
+++ b/docs/user/site.rst
@@ -213,12 +213,17 @@ This is a non-exhaustive list of site-repos from various communities:
 
 * `site-ffbs <https://github.com/ffbs/site-ffbs>`_ (Braunschweig)
 * `site-ffhb <https://github.com/FreifunkBremen/gluon-site-ffhb>`_ (Bremen)
+* `site-ffda <https://github.com/freifunk-darmstadt/site-ffda>`_ (Darmstadt)
 * `site-ffhh <https://github.com/freifunkhamburg/site-ffhh>`_ (Hamburg)
 * `site-ffhgw <https://github.com/lorenzo-greifswald/site-ffhgw>`_ (Greifswald)
 * `site-ffhl <https://github.com/freifunk-gluon/site-ffhl>`_ (Lübeck)
 * `site-ffmd <https://github.com/FreifunkMD/site-ffmd>`_ (Magdeburg)
 * `site-ffmz <https://github.com/freifunk-mwu/site-ffmz>`_ (Mainz, Wiesbaden & Umgebung)
 * `site-ffm <https://github.com/freifunkMUC/site-ffm>`_ (München)
+* `site-ffms <https://github.com/FreiFunkMuenster/site-ffms>`_ (Münster)
 * `site-ffnw <https://git.freifunk-ol.de/root/siteconf.git>`_ (Nordwest)
 * `site-ffpb <https://git.c3pb.de/freifunk-pb/site-ffpb>`_ (Paderborn)
 * `site-ffka <https://github.com/ffka/site-ffka>`_ (Karlsruhe)
+* `site-ffrl <https://github.com/ffrl/sites-ffrl>`_ (Rheinland)
+* `site-ffrg <https://github.com/ffruhr/site-ffruhr>`_ (Ruhrgebiet)
+* `site-ffs <https://github.com/freifunk-stuttgart/site-ffs>`_ (Stuttgart)
diff --git a/modules b/modules
index 377ec3599904adac4741fc0b7d1eb8ca69da385d..8a77946cc0c515f9ebfb15ecbfc98a2d2fa38dcd 100644
--- a/modules
+++ b/modules
@@ -1,18 +1,18 @@
 GLUON_FEEDS='openwrt gluon routing luci'
 
 OPENWRT_REPO=git://git.openwrt.org/14.07/openwrt.git
-OPENWRT_COMMIT=22808d019dc6d2afd8946036740ea3caf84e5f5b
+OPENWRT_COMMIT=678b8b53a3a79da8f0a7ee5da8f3918cbc00ac78
 
 PACKAGES_OPENWRT_REPO=git://github.com/openwrt/packages.git
-PACKAGES_OPENWRT_COMMIT=d83d5f680683c9266be8302e27e49e649ad871d9
+PACKAGES_OPENWRT_COMMIT=ad7c25a87faa72eef0ea23f19615a4651e0f3cb1
 PACKAGES_OPENWRT_BRANCH=for-14.07
 
 PACKAGES_GLUON_REPO=git://github.com/freifunk-gluon/packages.git
-PACKAGES_GLUON_COMMIT=8a349f41313b5b3b5e0f6738082c77e5d931459b
+PACKAGES_GLUON_COMMIT=9330e21bf0d5dd901f5447c0a101505eca13ddc9
 
 PACKAGES_ROUTING_REPO=git://github.com/openwrt-routing/packages.git
 PACKAGES_ROUTING_COMMIT=c08fe48bcd3a38d47387eb6dd8474770847e3b66
 PACKAGES_ROUTING_BRANCH=for-14.07
 
-PACKAGES_LUCI_REPO=git://git.openwrt.org/project/luci.git
-PACKAGES_LUCI_COMMIT=108a146a38f3facc9bdfe1542e6144dc49a67317
+PACKAGES_LUCI_REPO=git://github.com/openwrt/luci.git
+PACKAGES_LUCI_COMMIT=f81be49ae756dab82e1758a6c9de145f0d36960e
diff --git a/patches/openwrt/0001-tools-Makefile-fix-host-tools-build-dependencies.patch b/patches/openwrt/0001-tools-Makefile-fix-host-tools-build-dependencies.patch
index c8ae9cd3ba584ef8c83f83e1976cba2e58d3ec90..1a39c7bd5baf77f56fbfb3abfad62995849ed879 100644
--- a/patches/openwrt/0001-tools-Makefile-fix-host-tools-build-dependencies.patch
+++ b/patches/openwrt/0001-tools-Makefile-fix-host-tools-build-dependencies.patch
@@ -3,10 +3,10 @@ Date: Sat, 26 Jul 2014 06:10:23 +0200
 Subject: tools/Makefile: fix host tools build dependencies
 
 diff --git a/tools/Makefile b/tools/Makefile
-index 9595d62..b8eef3f 100644
+index 13bb028..137ad61 100644
 --- a/tools/Makefile
 +++ b/tools/Makefile
-@@ -96,10 +96,16 @@ define PrepareStaging
+@@ -97,10 +97,16 @@ define PrepareStaging
  endef
  
  # preparatory work
@@ -23,7 +23,7 @@ index 9595d62..b8eef3f 100644
  
  $(STAGING_DIR_HOST)/.prepared: $(TMP_DIR)/.build
  	$(call PrepareStaging,$(STAGING_DIR_HOST))
-@@ -111,7 +117,7 @@ $(STAGING_DIR_HOST)/.prepared: $(TMP_DIR)/.build
+@@ -112,7 +118,7 @@ $(STAGING_DIR_HOST)/.prepared: $(TMP_DIR)/.build
  
  
  define PrepareCommand
@@ -32,7 +32,7 @@ index 9595d62..b8eef3f 100644
  	@mkdir -p "$$(dir $$@)"; rm -f "$$@"
  	@export FILE="$$$$(which $(2) 2>/dev/null | grep -v 'not found' | head -n1)"; [ -n "$$$$FILE" ] || { \
  		echo "Command $(1) not found."; false; \
-@@ -120,7 +126,7 @@ $(STAGING_DIR_HOST)/bin/$(1): $(STAGING_DIR)/.prepared
+@@ -121,7 +127,7 @@ $(STAGING_DIR_HOST)/bin/$(1): $(STAGING_DIR)/.prepared
  endef
  endif
  
@@ -41,7 +41,7 @@ index 9595d62..b8eef3f 100644
  	@rm -f $@
  	@if stat --version > /dev/null 2>&1; then \
  		ln -s `which stat` $@; \
-@@ -144,8 +150,8 @@ $(eval $(call PrepareCommand,tar,gtar tar))
+@@ -145,8 +151,8 @@ $(eval $(call PrepareCommand,tar,gtar tar))
  $(eval $(call PrepareCommand,diff,gdiff diff))
  
  $(curdir)/cmddeps = $(patsubst %,$(STAGING_DIR_HOST)/bin/%,md5sum cp stat seq python awk getopt grep tar diff)
diff --git a/patches/openwrt/0004-odhcp6c-always-accept-RDNSS-independent-of-the-default-router-lifetime.patch b/patches/openwrt/0004-odhcp6c-always-accept-RDNSS-independent-of-the-default-router-lifetime.patch
new file mode 100644
index 0000000000000000000000000000000000000000..21c819188f5dd83513c433bbede9878e7ce883e7
--- /dev/null
+++ b/patches/openwrt/0004-odhcp6c-always-accept-RDNSS-independent-of-the-default-router-lifetime.patch
@@ -0,0 +1,26 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Thu, 13 Nov 2014 01:17:24 +0100
+Subject: odhcp6c: always accept RDNSS, independent of the default router lifetime
+
+diff --git a/package/network/ipv6/odhcp6c/patches/001-always_accept_rdnss.patch b/package/network/ipv6/odhcp6c/patches/001-always_accept_rdnss.patch
+new file mode 100644
+index 0000000..ae4e18d
+--- /dev/null
++++ b/package/network/ipv6/odhcp6c/patches/001-always_accept_rdnss.patch
+@@ -0,0 +1,16 @@
++--- a/src/ra.c
+++++ b/src/ra.c
++@@ -409,13 +409,6 @@ bool ra_process(void)
++ 				}
++ 			}
++ 		}
++-
++-		size_t ra_dns_len;
++-		struct odhcp6c_entry *entry = odhcp6c_get_state(STATE_RA_DNS, &ra_dns_len);
++-		for (size_t i = 0; i < ra_dns_len / sizeof(*entry); ++i)
++-			if (IN6_ARE_ADDR_EQUAL(&entry[i].router, &from.sin6_addr) &&
++-					entry[i].valid > router_valid)
++-				entry[i].valid = router_valid;
++ 	}
++ 
++ 	if (found)
diff --git a/patches/openwrt/0005-firmware-utils-add-new-tool-tplink-safeloader-for-the-new-TP-LINK-Pharos-devices-CPE210-220-510-520.patch b/patches/openwrt/0005-firmware-utils-add-new-tool-tplink-safeloader-for-the-new-TP-LINK-Pharos-devices-CPE210-220-510-520.patch
new file mode 100644
index 0000000000000000000000000000000000000000..9cc72b6b7a44e66112f012bd18fc935f1754d7ed
--- /dev/null
+++ b/patches/openwrt/0005-firmware-utils-add-new-tool-tplink-safeloader-for-the-new-TP-LINK-Pharos-devices-CPE210-220-510-520.patch
@@ -0,0 +1,570 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Wed, 26 Nov 2014 19:57:39 +0100
+Subject: firmware-utils: add new tool tplink-safeloader for the new TP-LINK Pharos devices (CPE210/220/510/520)
+
+The new TP-LINK Pharos series uses a new bootloader, the "TP-LINK Safeloader".
+It uses an advanced firmware image format, containing an image partition table
+and a flash partition table (and image partitions are mapped to the
+corresponding flash partitions). The exact image format is documented in the
+source code.
+
+Furthermore, the bootloader expects the kernel image as an ELF executable.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/tools/firmware-utils/Makefile b/tools/firmware-utils/Makefile
+index 4bb53cb..3f9eb56 100644
+--- a/tools/firmware-utils/Makefile
++++ b/tools/firmware-utils/Makefile
+@@ -41,6 +41,7 @@ define Host/Compile
+ 	$(call cc,mkplanexfw sha1)
+ 	$(call cc,mktplinkfw md5)
+ 	$(call cc,mktplinkfw2 md5)
++	$(call cc,tplink-safeloader md5, -Wall)
+ 	$(call cc,pc1crypt)
+ 	$(call cc,osbridge-crc)
+ 	$(call cc,wrt400n cyg_crc32)
+diff --git a/tools/firmware-utils/src/tplink-safeloader.c b/tools/firmware-utils/src/tplink-safeloader.c
+new file mode 100644
+index 0000000..23d703f
+--- /dev/null
++++ b/tools/firmware-utils/src/tplink-safeloader.c
+@@ -0,0 +1,538 @@
++/*
++  Copyright (c) 2014, Matthias Schiffer <mschiffer@universe-factory.net>
++  All rights reserved.
++
++  Redistribution and use in source and binary forms, with or without
++  modification, are permitted provided that the following conditions are met:
++
++    1. Redistributions of source code must retain the above copyright notice,
++       this list of conditions and the following disclaimer.
++    2. Redistributions in binary form must reproduce the above copyright notice,
++       this list of conditions and the following disclaimer in the documentation
++       and/or other materials provided with the distribution.
++
++  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
++  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
++  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
++  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
++  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
++  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++*/
++
++
++/*
++   tplink-safeloader
++
++   Image generation tool for the TP-LINK SafeLoader as seen on
++   TP-LINK Pharos devices (CPE210/220/510/520)
++*/
++
++
++#include <assert.h>
++#include <errno.h>
++#include <error.h>
++#include <stdbool.h>
++#include <stdio.h>
++#include <stdint.h>
++#include <stdlib.h>
++#include <string.h>
++#include <time.h>
++#include <unistd.h>
++
++#include <arpa/inet.h>
++
++#include <sys/types.h>
++#include <sys/stat.h>
++
++#include "md5.h"
++
++
++#define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); })
++
++
++/** An image partition table entry */
++struct image_partition_entry {
++	const char *name;
++	size_t size;
++	uint8_t *data;
++};
++
++/** A flash partition table entry */
++struct flash_partition_entry {
++	const char *name;
++	uint32_t base;
++	uint32_t size;
++};
++
++
++/** The content of the soft-version structure */
++struct __attribute__((__packed__)) soft_version {
++	uint32_t magic;
++	uint32_t zero;
++	uint8_t pad1;
++	uint8_t version_major;
++	uint8_t version_minor;
++	uint8_t version_patch;
++	uint8_t year_hi;
++	uint8_t year_lo;
++	uint8_t month;
++	uint8_t day;
++	uint32_t rev;
++	uint8_t pad2;
++};
++
++
++static const uint8_t jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde};
++
++
++/**
++   Salt for the MD5 hash
++
++   Fortunately, TP-LINK seems to use the same salt for most devices which use
++   the new image format.
++*/
++static const uint8_t md5_salt[16] = {
++	0x7a, 0x2b, 0x15, 0xed,
++	0x9b, 0x98, 0x59, 0x6d,
++	0xe5, 0x04, 0xab, 0x44,
++	0xac, 0x2a, 0x9f, 0x4e,
++};
++
++
++/** Vendor information for CPE210/220/510/520 */
++static const unsigned char cpe510_vendor[] = "\x00\x00\x00\x1f""CPE510(TP-LINK|UN|N300-5):1.0\r\n";
++
++
++/**
++    The flash partition table for CPE210/220/510/520;
++    it is the same as the one used by the stock images.
++*/
++static const struct flash_partition_entry cpe510_partitions[] = {
++	{"fs-uboot", 0x00000, 0x20000},
++	{"partition-table", 0x20000, 0x02000},
++	{"default-mac", 0x30000, 0x00020},
++	{"product-info", 0x31100, 0x00100},
++	{"signature", 0x32000, 0x00400},
++	{"os-image", 0x40000, 0x170000},
++	{"soft-version", 0x1b0000, 0x00100},
++	{"support-list", 0x1b1000, 0x00400},
++	{"file-system", 0x1c0000, 0x600000},
++	{"user-config", 0x7c0000, 0x10000},
++	{"default-config", 0x7d0000, 0x10000},
++	{"log", 0x7e0000, 0x10000},
++	{"radio", 0x7f0000, 0x10000},
++	{NULL, 0, 0}
++};
++
++/**
++   The support list for CPE210/220/510/520
++
++   The stock images also contain strings for two more devices: BS510 and BS210.
++   At the moment, there exists no public information about these devices.
++*/
++static const unsigned char cpe510_support_list[] =
++	"\x00\x00\x00\xc8\x00\x00\x00\x00"
++	"SupportList:\r\n"
++	"CPE510(TP-LINK|UN|N300-5):1.0\r\n"
++	"CPE520(TP-LINK|UN|N300-5):1.0\r\n"
++	"CPE210(TP-LINK|UN|N300-2):1.0\r\n"
++	"CPE220(TP-LINK|UN|N300-2):1.0\r\n"
++	"\r\n\xff";
++
++
++/** Allocates a new image partition */
++struct image_partition_entry alloc_image_partition(const char *name, size_t len) {
++	struct image_partition_entry entry = {name, len, malloc(len)};
++	if (!entry.data)
++		error(1, errno, "malloc");
++
++	return entry;
++}
++
++/** Frees an image partition */
++void free_image_partition(struct image_partition_entry entry) {
++	free(entry.data);
++}
++
++/** Generates the partition-table partition */
++struct image_partition_entry make_partition_table(const struct flash_partition_entry *p) {
++	struct image_partition_entry entry = alloc_image_partition("partition-table", 0x800);
++
++	char *s = (char *)entry.data, *end = (char *)(s+entry.size);
++
++	*(s++) = 0x00;
++	*(s++) = 0x04;
++	*(s++) = 0x00;
++	*(s++) = 0x00;
++
++	size_t i;
++	for (i = 0; p[i].name; i++) {
++		size_t len = end-s;
++		size_t w = snprintf(s, len, "partition %s base 0x%05x size 0x%05x\n", p[i].name, p[i].base, p[i].size);
++
++		if (w > len-1)
++			error(1, 0, "flash partition table overflow?");
++
++		s += w;
++	}
++
++	s++;
++
++	memset(s, 0xff, end-s);
++
++	return entry;
++}
++
++
++/** Generates a binary-coded decimal representation of an integer in the range [0, 99] */
++static inline uint8_t bcd(uint8_t v) {
++	return 0x10 * (v/10) + v%10;
++}
++
++
++/** Generates the soft-version partition */
++struct image_partition_entry make_soft_version(uint32_t rev) {
++	struct image_partition_entry entry = alloc_image_partition("soft-version", sizeof(struct soft_version));
++	struct soft_version *s = (struct soft_version *)entry.data;
++
++	time_t t;
++	if (time(&t) == (time_t)(-1))
++		error(1, errno, "time");
++
++	struct tm *tm = localtime(&t);
++
++	s->magic = htonl(0x0000000c);
++	s->zero = 0;
++	s->pad1 = 0xff;
++
++	s->version_major = 0;
++	s->version_minor = 0;
++	s->version_patch = 0;
++
++	s->year_hi = bcd((1900+tm->tm_year)/100);
++	s->year_lo = bcd(tm->tm_year%100);
++	s->month = bcd(tm->tm_mon+1);
++	s->day = bcd(tm->tm_mday);
++	s->rev = htonl(rev);
++
++	s->pad2 = 0xff;
++
++	return entry;
++}
++
++/** Generates the support-list partition */
++struct image_partition_entry make_support_list(const unsigned char *support_list, size_t len) {
++	struct image_partition_entry entry = alloc_image_partition("support-list", len);
++	memcpy(entry.data, support_list, len);
++	return entry;
++}
++
++/** Creates a new image partition with an arbitrary name from a file */
++struct image_partition_entry read_file(const char *part_name, const char *filename, bool add_jffs2_eof) {
++	struct stat statbuf;
++
++	if (stat(filename, &statbuf) < 0)
++		error(1, errno, "unable to stat file `%s'", filename);
++
++	size_t len = statbuf.st_size;
++
++	if (add_jffs2_eof)
++		len = ALIGN(len, 0x10000) + sizeof(jffs2_eof_mark);
++
++	struct image_partition_entry entry = alloc_image_partition(part_name, len);
++
++	FILE *file = fopen(filename, "rb");
++	if (!file)
++		error(1, errno, "unable to open file `%s'", filename);
++
++	if (fread(entry.data, statbuf.st_size, 1, file) != 1)
++		error(1, errno, "unable to read file `%s'", filename);
++
++	if (add_jffs2_eof) {
++		uint8_t *eof = entry.data + statbuf.st_size, *end = entry.data+entry.size;
++
++		memset(eof, 0xff, end - eof - sizeof(jffs2_eof_mark));
++		memcpy(end - sizeof(jffs2_eof_mark), jffs2_eof_mark, sizeof(jffs2_eof_mark));
++	}
++
++	fclose(file);
++
++	return entry;
++}
++
++
++/**
++   Copies a list of image partitions into an image buffer and generates the image partition table while doing so
++
++   Example image partition table:
++
++     fwup-ptn partition-table base 0x00800 size 0x00800
++     fwup-ptn os-image base 0x01000 size 0x113b45
++     fwup-ptn file-system base 0x114b45 size 0x1d0004
++     fwup-ptn support-list base 0x2e4b49 size 0x000d1
++
++   Each line of the partition table is terminated with the bytes 09 0d 0a ("\t\r\n"),
++   the end of the partition table is marked with a zero byte.
++
++   The firmware image must contain at least the partition-table and support-list partitions
++   to be accepted. There aren't any alignment constraints for the image partitions.
++
++   The partition-table partition contains the actual flash layout; partitions
++   from the image partition table are mapped to the corresponding flash partitions during
++   the firmware upgrade. The support-list partition contains a list of devices supported by
++   the firmware image.
++
++   The base offsets in the firmware partition table are relative to the end
++   of the vendor information block, so the partition-table partition will
++   actually start at offset 0x1814 of the image.
++
++   I think partition-table must be the first partition in the firmware image.
++*/
++void put_partitions(uint8_t *buffer, const struct image_partition_entry *parts) {
++	size_t i;
++	char *image_pt = (char *)buffer, *end = image_pt + 0x800;
++
++	size_t base = 0x800;
++	for (i = 0; parts[i].name; i++) {
++		memcpy(buffer + base, parts[i].data, parts[i].size);
++
++		size_t len = end-image_pt;
++		size_t w = snprintf(image_pt, len, "fwup-ptn %s base 0x%05x size 0x%05x\t\r\n", parts[i].name, (unsigned)base, (unsigned)parts[i].size);
++
++		if (w > len-1)
++			error(1, 0, "image partition table overflow?");
++
++		image_pt += w;
++
++		base += parts[i].size;
++	}
++
++	image_pt++;
++
++	memset(image_pt, 0xff, end-image_pt);
++}
++
++/** Generates and writes the image MD5 checksum */
++void put_md5(uint8_t *md5, uint8_t *buffer, unsigned int len) {
++	MD5_CTX ctx;
++
++	MD5_Init(&ctx);
++	MD5_Update(&ctx, md5_salt, (unsigned int)sizeof(md5_salt));
++	MD5_Update(&ctx, buffer, len);
++	MD5_Final(md5, &ctx);
++}
++
++
++/**
++   Generates the firmware image in factory format
++
++   Image format:
++
++     Bytes (hex)  Usage
++     -----------  -----
++     0000-0003    Image size (4 bytes, big endian)
++     0004-0013    MD5 hash (hash of a 16 byte salt and the image data starting with byte 0x14)
++     0014-1013    Vendor information (4096 bytes, padded with 0xff; there seem to be older
++                  (VxWorks-based) TP-LINK devices which use a smaller vendor information block)
++     1014-1813    Image partition table (2048 bytes, padded with 0xff)
++     1814-xxxx    Firmware partitions
++*/
++void * generate_factory_image(const unsigned char *vendor, size_t vendor_len, const struct image_partition_entry *parts, size_t *len) {
++	*len = 0x1814;
++
++	size_t i;
++	for (i = 0; parts[i].name; i++)
++		*len += parts[i].size;
++
++	uint8_t *image = malloc(*len);
++	if (!image)
++		error(1, errno, "malloc");
++
++	image[0] = *len >> 24;
++	image[1] = *len >> 16;
++	image[2] = *len >> 8;
++	image[3] = *len;
++
++	memcpy(image+0x14, vendor, vendor_len);
++	memset(image+0x14+vendor_len, 0xff, 4096-vendor_len);
++
++	put_partitions(image + 0x1014, parts);
++	put_md5(image+0x04, image+0x14, *len-0x14);
++
++	return image;
++}
++
++/**
++   Generates the firmware image in sysupgrade format
++
++   This makes some assumptions about the provided flash and image partition tables and
++   should be generalized when TP-LINK starts building its safeloader into hardware with
++   different flash layouts.
++*/
++void * generate_sysupgrade_image(const struct flash_partition_entry *flash_parts, const struct image_partition_entry *image_parts, size_t *len) {
++	const struct flash_partition_entry *flash_os_image = &flash_parts[5];
++	const struct flash_partition_entry *flash_soft_version = &flash_parts[6];
++	const struct flash_partition_entry *flash_support_list = &flash_parts[7];
++	const struct flash_partition_entry *flash_file_system = &flash_parts[8];
++
++	const struct image_partition_entry *image_os_image = &image_parts[3];
++	const struct image_partition_entry *image_soft_version = &image_parts[1];
++	const struct image_partition_entry *image_support_list = &image_parts[2];
++	const struct image_partition_entry *image_file_system = &image_parts[4];
++
++	assert(strcmp(flash_os_image->name, "os-image") == 0);
++	assert(strcmp(flash_soft_version->name, "soft-version") == 0);
++	assert(strcmp(flash_support_list->name, "support-list") == 0);
++	assert(strcmp(flash_file_system->name, "file-system") == 0);
++
++	assert(strcmp(image_os_image->name, "os-image") == 0);
++	assert(strcmp(image_soft_version->name, "soft-version") == 0);
++	assert(strcmp(image_support_list->name, "support-list") == 0);
++	assert(strcmp(image_file_system->name, "file-system") == 0);
++
++	if (image_os_image->size > flash_os_image->size)
++		error(1, 0, "kernel image too big (more than %u bytes)", (unsigned)flash_os_image->size);
++	if (image_file_system->size > flash_file_system->size)
++		error(1, 0, "rootfs image too big (more than %u bytes)", (unsigned)flash_file_system->size);
++
++	*len = flash_file_system->base - flash_os_image->base + image_file_system->size;
++
++	uint8_t *image = malloc(*len);
++	if (!image)
++		error(1, errno, "malloc");
++
++	memset(image, 0xff, *len);
++
++	memcpy(image, image_os_image->data, image_os_image->size);
++	memcpy(image + flash_soft_version->base - flash_os_image->base, image_soft_version->data, image_soft_version->size);
++	memcpy(image + flash_support_list->base - flash_os_image->base, image_support_list->data, image_support_list->size);
++	memcpy(image + flash_file_system->base - flash_os_image->base, image_file_system->data, image_file_system->size);
++
++	return image;
++}
++
++
++/** Generates an image for CPE210/220/510/520 and writes it to a file */
++static void do_cpe510(const char *output, const char *kernel_image, const char *rootfs_image, uint32_t rev, bool add_jffs2_eof, bool sysupgrade) {
++	struct image_partition_entry parts[6] = {};
++
++	parts[0] = make_partition_table(cpe510_partitions);
++	parts[1] = make_soft_version(rev);
++	parts[2] = make_support_list(cpe510_support_list, sizeof(cpe510_support_list)-1);
++	parts[3] = read_file("os-image", kernel_image, false);
++	parts[4] = read_file("file-system", rootfs_image, add_jffs2_eof);
++
++	size_t len;
++	void *image;
++	if (sysupgrade)
++		image = generate_sysupgrade_image(cpe510_partitions, parts, &len);
++	else
++		image = generate_factory_image(cpe510_vendor, sizeof(cpe510_vendor)-1, parts, &len);
++
++	FILE *file = fopen(output, "wb");
++	if (!file)
++		error(1, errno, "unable to open output file");
++
++	if (fwrite(image, len, 1, file) != 1)
++		error(1, 0, "unable to write output file");
++
++	fclose(file);
++
++	free(image);
++
++	size_t i;
++	for (i = 0; parts[i].name; i++)
++		free_image_partition(parts[i]);
++}
++
++
++/** Usage output */
++void usage(const char *argv0) {
++	fprintf(stderr,
++		"Usage: %s [OPTIONS...]\n"
++		"\n"
++		"Options:\n"
++		"  -B <board>      create image for the board specified with <board>\n"
++		"  -k <file>       read kernel image from the file <file>\n"
++		"  -r <file>       read rootfs image from the file <file>\n"
++		"  -o <file>       write output to the file <file>\n"
++		"  -V <rev>        sets the revision number to <rev>\n"
++		"  -j              add jffs2 end-of-filesystem markers\n"
++		"  -S              create sysupgrade instead of factory image\n"
++		"  -h              show this help\n",
++		argv0
++	);
++};
++
++
++int main(int argc, char *argv[]) {
++	const char *board = NULL, *kernel_image = NULL, *rootfs_image = NULL, *output = NULL;
++	bool add_jffs2_eof = false, sysupgrade = false;
++	unsigned rev = 0;
++
++	while (true) {
++		int c;
++
++		c = getopt(argc, argv, "B:k:r:o:V:jSh");
++		if (c == -1)
++			break;
++
++		switch (c) {
++		case 'B':
++			board = optarg;
++			break;
++
++		case 'k':
++			kernel_image = optarg;
++			break;
++
++		case 'r':
++			rootfs_image = optarg;
++			break;
++
++		case 'o':
++			output = optarg;
++			break;
++
++		case 'V':
++			sscanf(optarg, "r%u", &rev);
++			break;
++
++		case 'j':
++			add_jffs2_eof = true;
++			break;
++
++		case 'S':
++			sysupgrade = true;
++			break;
++
++		case 'h':
++			usage(argv[0]);
++			return 0;
++
++		default:
++			usage(argv[0]);
++			return 1;
++		}
++	}
++
++	if (!board)
++		error(1, 0, "no board has been specified");
++	if (!kernel_image)
++		error(1, 0, "no kernel image has been specified");
++	if (!rootfs_image)
++		error(1, 0, "no rootfs image has been specified");
++	if (!output)
++		error(1, 0, "no output filename has been specified");
++
++	if (strcmp(board, "CPE510") == 0)
++		do_cpe510(output, kernel_image, rootfs_image, rev, add_jffs2_eof, sysupgrade);
++	else
++		error(1, 0, "unsupported board %s", board);
++
++	return 0;
++}
diff --git a/patches/openwrt/0006-ar71xx-add-support-for-TP-LINK-CPE210-220-510-520.patch b/patches/openwrt/0006-ar71xx-add-support-for-TP-LINK-CPE210-220-510-520.patch
new file mode 100644
index 0000000000000000000000000000000000000000..1673562fcf5a626b297396a5b89018fb58a750ac
--- /dev/null
+++ b/patches/openwrt/0006-ar71xx-add-support-for-TP-LINK-CPE210-220-510-520.patch
@@ -0,0 +1,471 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Wed, 26 Nov 2014 19:57:50 +0100
+Subject: ar71xx: add support for TP-LINK CPE210/220/510/520
+
+This adds support for the TP-LINK CPE210/220/510/520 (Pharos series). These
+devices are very similar to the Ubiquiti NanoStations, but with better specs:
+faster CPU, more RAM, 2x2 MIMO.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+
+diff --git a/target/linux/ar71xx/base-files/etc/diag.sh b/target/linux/ar71xx/base-files/etc/diag.sh
+index 1864b11..4b510dd 100755
+--- a/target/linux/ar71xx/base-files/etc/diag.sh
++++ b/target/linux/ar71xx/base-files/etc/diag.sh
+@@ -43,6 +43,9 @@ get_status_led() {
+ 	cap4200ag)
+ 		status_led="senao:green:pwr"
+ 		;;
++	cpe510)
++		status_led="tp-link:green:link4"
++		;;
+ 	db120)
+ 		status_led="db120:green:status"
+ 		;;
+diff --git a/target/linux/ar71xx/base-files/etc/uci-defaults/01_leds b/target/linux/ar71xx/base-files/etc/uci-defaults/01_leds
+index d3b766d..fb8df40 100755
+--- a/target/linux/ar71xx/base-files/etc/uci-defaults/01_leds
++++ b/target/linux/ar71xx/base-files/etc/uci-defaults/01_leds
+@@ -61,6 +61,16 @@ carambola2)
+ 	ucidef_set_led_wlan "wlan" "WLAN" "carambola2:green:wlan" "phy0tpt"
+ 	;;
+ 
++cpe510)
++	ucidef_set_led_switch "lan0" "LAN0" "tp-link:green:lan0" "switch0" "0x20"
++	ucidef_set_led_switch "lan1" "LAN1" "tp-link:green:lan1" "switch0" "0x10"
++	ucidef_set_rssimon "wlan0" "40000" "1"
++	ucidef_set_led_rssi "rssilow" "RSSILOW" "tp-link:green:link1" "wlan0" "1" "100" "0" "13"
++	ucidef_set_led_rssi "rssimediumlow" "RSSIMEDIUMLOW" "tp-link:green:link2" "wlan0" "26" "100" "-25" "13"
++	ucidef_set_led_rssi "rssimediumhigh" "RSSIMEDIUMHIGH" "tp-link:green:link3" "wlan0" "51" "100" "-50" "13"
++	ucidef_set_led_rssi "rssihigh" "RSSIHIGH" "tp-link:green:link4" "wlan0" "76" "100" "-75" "13"
++	;;
++
+ db120)
+ 	ucidef_set_led_usbdev "usb" "USB" "db120:green:usb" "1-1"
+ 	;;
+diff --git a/target/linux/ar71xx/base-files/etc/uci-defaults/02_network b/target/linux/ar71xx/base-files/etc/uci-defaults/02_network
+index c5cfd67..a9f00fa 100755
+--- a/target/linux/ar71xx/base-files/etc/uci-defaults/02_network
++++ b/target/linux/ar71xx/base-files/etc/uci-defaults/02_network
+@@ -62,6 +62,13 @@ tl-wdr4900-v2)
+ 	ucidef_add_switch_vlan "switch0" "2" "1 6"
+ 	;;
+ 
++cpe510)
++	ucidef_set_interfaces_lan_wan "eth0.1" "eth0.2"
++	ucidef_add_switch "switch0" "1" "1"
++	ucidef_add_switch_vlan "switch0" "1" "0t 5"
++	ucidef_add_switch_vlan "switch0" "2" "0t 4"
++	;;
++
+ db120 |\
+ rb-2011l | \
+ rb-2011uas |\
+diff --git a/target/linux/ar71xx/base-files/lib/ar71xx.sh b/target/linux/ar71xx/base-files/lib/ar71xx.sh
+index 5aceaee..0b0a8d6 100755
+--- a/target/linux/ar71xx/base-files/lib/ar71xx.sh
++++ b/target/linux/ar71xx/base-files/lib/ar71xx.sh
+@@ -229,6 +229,39 @@ tplink_board_detect() {
+ 	AR71XX_MODEL="$model $hwver"
+ }
+ 
++tplink_pharos_get_model_string() {
++	local part
++	part=$(find_mtd_part 'product-info')
++	[ -z "$part" ] && return 1
++
++	# The returned string will end with \r\n, but we don't remove it here
++	# to simplify matching against it in the sysupgrade image check
++	dd if=$part bs=1 skip=4360 2>/dev/null | head -n 1
++}
++
++tplink_pharos_board_detect() {
++	local model_string="$(tplink_pharos_get_model_string | tr -d '\r')"
++	local oIFS="$IFS"; IFS=":"; set -- $model_string; IFS="$oIFS"
++	local model
++
++	case "$1" in
++	'CPE210(TP-LINK|UN|N300-2)')
++		model='TP-Link CPE210'
++		;;
++	'CPE220(TP-LINK|UN|N300-2)')
++		model='TP-Link CPE220'
++		;;
++	'CPE510(TP-LINK|UN|N300-5)')
++		model='TP-Link CPE510'
++		;;
++	'CPE520(TP-LINK|UN|N300-5)')
++		model='TP-Link CPE520'
++		;;
++	esac
++
++	[ -n "$model" ] && AR71XX_MODEL="$model v$2"
++}
++
+ ar71xx_board_detect() {
+ 	local machine
+ 	local name
+@@ -302,6 +335,10 @@ ar71xx_board_detect() {
+ 	*CAP4200AG)
+ 		name="cap4200ag"
+ 		;;
++	*"CPE210/220/510/520")
++		name="cpe510"
++		tplink_pharos_board_detect
++		;;
+ 	*"DB120 reference board")
+ 		name="db120"
+ 		;;
+@@ -751,11 +788,8 @@ ar71xx_board_detect() {
+ 		;;
+ 	esac
+ 
+-	case "$machine" in
+-	*TL-WR* | *TL-WA* | *TL-MR* | *TL-WD* | *Archer*)
++	[ -z "$AR71XX_MODEL" ] && [ "${machine:0:8}" = 'TP-LINK ' ] && \
+ 		tplink_board_detect "$machine"
+-		;;
+-	esac
+ 
+ 	[ -z "$name" ] && name="unknown"
+ 
+diff --git a/target/linux/ar71xx/base-files/lib/upgrade/platform.sh b/target/linux/ar71xx/base-files/lib/upgrade/platform.sh
+index 846954c..15e998c 100755
+--- a/target/linux/ar71xx/base-files/lib/upgrade/platform.sh
++++ b/target/linux/ar71xx/base-files/lib/upgrade/platform.sh
+@@ -70,6 +70,33 @@ tplink_get_image_boot_size() {
+ 	get_image "$@" | dd bs=4 count=1 skip=37 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
+ }
+ 
++tplink_pharos_check_image() {
++	local magic_long="$(get_magic_long "$1")"
++	[ "$magic_long" != "7f454c46" ] && {
++		echo "Invalid image magic '$magic_long'"
++		return 1
++	}
++
++	local model_string="$(tplink_pharos_get_model_string)"
++	local line
++
++	# Here $1 is given to dd directly instead of get_image as otherwise the skip
++	# will take almost a second (as dd can't seek then)
++	#
++	# This will fail if the image isn't local, but that's fine: as the
++	# read loop won't be executed at all, it will return true, so the image
++	# is accepted (loading the first 1.5M of a remote image for this check seems
++	# a bit extreme)
++	dd if="$1" bs=1 skip=1511432 count=1024 2>/dev/null | while read line; do
++		[ "$line" == "$model_string" ] && break
++	done || {
++		echo "Unsupported image (model not in support-list)"
++		return 1
++	}
++
++	return 0
++}
++
+ seama_get_type_magic() {
+ 	get_image "$@" | dd bs=1 count=4 skip=53 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'
+ }
+@@ -214,6 +241,11 @@ platform_check_image() {
+ 		return 0
+ 		;;
+ 
++	cpe510)
++		tplink_pharos_check_image "$1" && return 0
++		return 1
++		;;
++
+ 	dir-825-b1 | \
+ 	tew-673gru)
+ 		dir825b_check_image "$1" && return 0
+diff --git a/target/linux/ar71xx/config-3.10 b/target/linux/ar71xx/config-3.10
+index 9a8378a..2f05ec6 100644
+--- a/target/linux/ar71xx/config-3.10
++++ b/target/linux/ar71xx/config-3.10
+@@ -39,6 +39,7 @@ CONFIG_ATH79_MACH_AW_NR580=y
+ CONFIG_ATH79_MACH_BHU_BXU2000N2_A=y
+ CONFIG_ATH79_MACH_CAP4200AG=y
+ CONFIG_ATH79_MACH_CARAMBOLA2=y
++CONFIG_ATH79_MACH_CPE510=y
+ CONFIG_ATH79_MACH_DB120=y
+ CONFIG_ATH79_MACH_DIR_505_A1=y
+ CONFIG_ATH79_MACH_DIR_600_A1=y
+diff --git a/target/linux/ar71xx/files/arch/mips/ath79/mach-cpe510.c b/target/linux/ar71xx/files/arch/mips/ath79/mach-cpe510.c
+new file mode 100644
+index 0000000..8bf5c0f
+--- /dev/null
++++ b/target/linux/ar71xx/files/arch/mips/ath79/mach-cpe510.c
+@@ -0,0 +1,107 @@
++/*
++ *  TP-LINK CPE210/220/510/520 board support
++ *
++ *  Copyright (C) 2014 Matthias Schiffer <mschiffer@universe-factory.net>
++ *
++ *  This program is free software; you can redistribute it and/or modify it
++ *  under the terms of the GNU General Public License version 2 as published
++ *  by the Free Software Foundation.
++ */
++
++#include <linux/gpio.h>
++#include <linux/platform_device.h>
++
++#include <asm/mach-ath79/ath79.h>
++#include <asm/mach-ath79/ar71xx_regs.h>
++
++#include "common.h"
++#include "dev-eth.h"
++#include "dev-gpio-buttons.h"
++#include "dev-leds-gpio.h"
++#include "dev-m25p80.h"
++#include "dev-wmac.h"
++#include "machtypes.h"
++
++
++#define CPE510_GPIO_LED_LAN0	11
++#define CPE510_GPIO_LED_LAN1	12
++#define CPE510_GPIO_LED_L1	13
++#define CPE510_GPIO_LED_L2	14
++#define CPE510_GPIO_LED_L3	15
++#define CPE510_GPIO_LED_L4	16
++
++#define CPE510_GPIO_BTN_RESET	4
++
++#define CPE510_KEYS_POLL_INTERVAL	20 /* msecs */
++#define CPE510_KEYS_DEBOUNCE_INTERVAL	(3 * CPE510_KEYS_POLL_INTERVAL)
++
++
++static struct gpio_led cpe510_leds_gpio[] __initdata = {
++	{
++		.name		= "tp-link:green:lan0",
++		.gpio		= CPE510_GPIO_LED_LAN0,
++		.active_low	= 1,
++	}, {
++		.name		= "tp-link:green:lan1",
++		.gpio		= CPE510_GPIO_LED_LAN1,
++		.active_low	= 1,
++	}, {
++		.name		= "tp-link:green:link1",
++		.gpio		= CPE510_GPIO_LED_L1,
++		.active_low	= 1,
++	}, {
++		.name		= "tp-link:green:link2",
++		.gpio		= CPE510_GPIO_LED_L2,
++		.active_low	= 1,
++	}, {
++		.name		= "tp-link:green:link3",
++		.gpio		= CPE510_GPIO_LED_L3,
++		.active_low	= 1,
++	}, {
++		.name		= "tp-link:green:link4",
++		.gpio		= CPE510_GPIO_LED_L4,
++		.active_low	= 1,
++	},
++};
++
++static struct gpio_keys_button cpe510_gpio_keys[] __initdata = {
++	{
++		.desc		= "Reset button",
++		.type		= EV_KEY,
++		.code		= KEY_RESTART,
++		.debounce_interval = CPE510_KEYS_DEBOUNCE_INTERVAL,
++		.gpio		= CPE510_GPIO_BTN_RESET,
++		.active_low	= 1,
++	}
++};
++
++
++static void __init cpe510_setup(void)
++{
++	u8 *mac = (u8 *) KSEG1ADDR(0x1f830008);
++	u8 *ee = (u8 *) KSEG1ADDR(0x1fff1000);
++
++	/* Disable JTAG, enabling GPIOs 0-3 */
++	/* Configure OBS4 line, for GPIO 4*/
++	ath79_gpio_function_setup(AR934X_GPIO_FUNC_JTAG_DISABLE,
++				  AR934X_GPIO_FUNC_CLK_OBS4_EN);
++
++	ath79_register_leds_gpio(-1, ARRAY_SIZE(cpe510_leds_gpio),
++				 cpe510_leds_gpio);
++
++	ath79_register_gpio_keys_polled(1, CPE510_KEYS_POLL_INTERVAL,
++					ARRAY_SIZE(cpe510_gpio_keys),
++					cpe510_gpio_keys);
++
++	ath79_register_m25p80(NULL);
++
++	ath79_register_mdio(1, 0);
++	ath79_init_mac(ath79_eth1_data.mac_addr, mac, 0);
++	ath79_eth1_data.phy_if_mode = PHY_INTERFACE_MODE_GMII;
++	ath79_register_eth(1);
++
++	ath79_register_wmac(ee, mac);
++}
++
++MIPS_MACHINE(ATH79_MACH_CPE510, "CPE510", "TP-LINK CPE210/220/510/520",
++	     cpe510_setup);
+diff --git a/target/linux/ar71xx/generic/profiles/tp-link.mk b/target/linux/ar71xx/generic/profiles/tp-link.mk
+index 78333be..a9d170c 100644
+--- a/target/linux/ar71xx/generic/profiles/tp-link.mk
++++ b/target/linux/ar71xx/generic/profiles/tp-link.mk
+@@ -16,6 +16,17 @@ endef
+ $(eval $(call Profile,ARCHERC7))
+ 
+ 
++define Profile/CPE510
++	NAME:=TP-LINK CPE210/220/510/520
++	PACKAGES:=rssileds
++endef
++
++define Profile/CPE510/Description
++	Package set optimized for the TP-LINK CPE210/220/510/520.
++endef
++$(eval $(call Profile,CPE510))
++
++
+ define Profile/TLMR10U
+ 	NAME:=TP-LINK TL-MR10U
+ 	PACKAGES:=kmod-usb-core kmod-usb2
+diff --git a/target/linux/ar71xx/image/Makefile b/target/linux/ar71xx/image/Makefile
+index 683c238..5ff7f35 100644
+--- a/target/linux/ar71xx/image/Makefile
++++ b/target/linux/ar71xx/image/Makefile
+@@ -261,6 +261,7 @@ cameo_ap121_mtdlayout_8M=mtdparts=spi0.0:64k(u-boot)ro,64k(art)ro,64k(mac)ro,64k
+ cameo_db120_mtdlayout=mtdparts=spi0.0:64k(uboot)ro,64k(nvram)ro,15936k(firmware),192k(lang)ro,64k(mac)ro,64k(art)ro
+ cameo_db120_mtdlayout_8M=mtdparts=spi0.0:64k(uboot)ro,64k(nvram)ro,7872k(firmware),128k(lang)ro,64k(art)ro
+ cap4200ag_mtdlayout=mtdparts=spi0.0:256k(u-boot),64k(u-boot-env),320k(custom)ro,1536k(kernel),12096k(rootfs),2048k(failsafe),64k(art),13632k@0xa0000(firmware)
++cpe510_mtdlayout=mtdparts=spi0.0:128k(u-boot)ro,64k(pation-table)ro,64k(product-info)ro,1536k(kernel),6144k(rootfs),192k(config)ro,64k(ART)ro,7680k@0x40000(firmware)
+ eap300v2_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env),320k(custom),13632k(firmware),2048k(failsafe),64k(art)ro
+ db120_mtdlayout=mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,6336k(rootfs),1408k(kernel),64k(nvram),64k(art)ro,7744k@0x50000(firmware)
+ cameo_ap94_mtdlayout=mtdparts=spi0.0:256k(uboot)ro,64k(config)ro,6208k(firmware),64k(caldata)ro,1600k(unknown)ro,64k@0x7f0000(caldata_copy)
+@@ -811,6 +812,32 @@ define Image/Build/TPLINK-LZMA/initramfs
+ endef
+ 
+ 
++Image/Build/TPLINK-SAFELOADER/buildkernel=$(call PatchKernelLzma,$(2),$(3) $(4))
++
++define Image/Build/TPLINK-SAFELOADER
++	-rm -rf $(KDIR)/lzma-loader
++	$(LOADER_MAKE) LOADER=loader-$(2).elf\
++		LZMA_TEXT_START=0x80a00000 LOADADDR=0x80060000 \
++		LOADER_DATA="$(KDIR_TMP)/vmlinux-$(2).bin.lzma" BOARD="$(2)" \
++		compile loader.elf
++
++	-$(STAGING_DIR_HOST)/bin/tplink-safeloader \
++		-B $(5) \
++		-k $(KDIR)/loader-$(2).elf \
++		-r $(KDIR)/root.$(1) \
++		-V $(REVISION) \
++		-j \
++		-o $(call factoryname,$(1),$(2))
++	-$(STAGING_DIR_HOST)/bin/tplink-safeloader \
++		-B $(5) \
++		-k $(KDIR)/loader-$(2).elf \
++		-r $(KDIR)/root.$(1) \
++		-V $(REVISION) \
++		-j -S \
++		-o $(call sysupname,$(1),$(2))
++endef
++
++
+ define Image/Build/CyberTAN
+ 	echo -n '' > $(KDIR_TMP)/empty.bin
+ 	$(STAGING_DIR_HOST)/bin/trx -o $(KDIR)/image.tmp \
+@@ -1226,6 +1253,8 @@ $(eval $(call SingleProfile,TPLINK-LZMA,64kraw,TLWDR4310V1,tl-wdr4310-v1,TL-WDR4
+ $(eval $(call SingleProfile,TPLINK-LZMA,64kraw,TLWDR4900V2,tl-wdr4900-v2,TL-WDR4900-v2,ttyS0,115200,0x49000002,1,8Mlzma))
+ $(eval $(call SingleProfile,TPLINK-LZMA,64kraw,MW4530RV1,mw4530r-v1,TL-WDR4300,ttyS0,115200,0x45300001,1,8Mlzma))
+ 
++$(eval $(call SingleProfile,TPLINK-SAFELOADER,64kraw,CPE510,cpe210-220-510-520,CPE510,ttyS0,115200,$$(cpe510_mtdlayout),CPE510))
++
+ $(eval $(call SingleProfile,TPLINK-LZMA,64kraw,SMART-300,smart-300,SMART-300,ttyS0,115200,0x93410001,1,8Mlzma))
+ 
+ $(eval $(call SingleProfile,TPLINK-LZMA,64kraw,OOLITE,oolite,GS-OOLITE,ttyATH0,115200,0x3C000101,1,16Mlzma))
+diff --git a/target/linux/ar71xx/patches-3.10/610-MIPS-ath79-openwrt-machines.patch b/target/linux/ar71xx/patches-3.10/610-MIPS-ath79-openwrt-machines.patch
+index 3669f26..516d52d 100644
+--- a/target/linux/ar71xx/patches-3.10/610-MIPS-ath79-openwrt-machines.patch
++++ b/target/linux/ar71xx/patches-3.10/610-MIPS-ath79-openwrt-machines.patch
+@@ -1,6 +1,6 @@
+ --- a/arch/mips/ath79/machtypes.h
+ +++ b/arch/mips/ath79/machtypes.h
+-@@ -16,22 +16,144 @@
++@@ -16,22 +16,145 @@
+  
+  enum ath79_mach_type {
+  	ATH79_MACH_GENERIC = 0,
+@@ -24,6 +24,7 @@
+ +	ATH79_MACH_BHU_BXU2000N2_A1,	/* BHU BXU2000n-2 A1 */
+ +	ATH79_MACH_CAP4200AG,		/* Senao CAP4200AG */
+ +	ATH79_MACH_CARAMBOLA2,		/* 8devices Carambola2 */
+++	ATH79_MACH_CPE510,		/* TP-LINK CPE510 */
+  	ATH79_MACH_DB120,		/* Atheros DB120 reference board */
+  	ATH79_MACH_PB44,		/* Atheros PB44 reference board */
+ +	ATH79_MACH_DIR_505_A1,		/* D-Link DIR-505 rev. A1 */
+@@ -209,7 +210,7 @@
+  config ATH79_MACH_AP121
+  	bool "Atheros AP121 reference board"
+  	select SOC_AR933X
+-@@ -9,64 +64,736 @@ config ATH79_MACH_AP121
++@@ -9,64 +64,745 @@ config ATH79_MACH_AP121
+  	select ATH79_DEV_GPIO_BUTTONS
+  	select ATH79_DEV_LEDS_GPIO
+  	select ATH79_DEV_M25P80
+@@ -709,6 +710,15 @@
+  
+ -config ATH79_MACH_AP81
+ -	bool "Atheros AP81 reference board"
+++config ATH79_MACH_CPE510
+++       bool "TP-LINK CPE510 support"
+++       select SOC_AR934X
+++       select ATH79_DEV_ETH
+++       select ATH79_DEV_GPIO_BUTTONS
+++       select ATH79_DEV_LEDS_GPIO
+++       select ATH79_DEV_M25P80
+++       select ATH79_DEV_WMAC
+++
+ +config ATH79_MACH_TL_MR11U
+ +	bool "TP-LINK TL-MR11U/TL-MR3040 support"
+ +	select SOC_AR933X
+@@ -972,7 +982,7 @@
+  
+  config ATH79_MACH_UBNT_XM
+  	bool "Ubiquiti Networks XM/UniFi boards"
+-@@ -83,6 +810,65 @@ config ATH79_MACH_UBNT_XM
++@@ -83,6 +819,65 @@ config ATH79_MACH_UBNT_XM
+  	  Say 'Y' here if you want your kernel to support the
+  	  Ubiquiti Networks XM (rev 1.0) board.
+  
+@@ -1038,7 +1048,7 @@
+  endmenu
+  
+  config SOC_AR71XX
+-@@ -132,7 +918,10 @@ config ATH79_DEV_DSA
++@@ -132,7 +927,10 @@ config ATH79_DEV_DSA
+  config ATH79_DEV_ETH
+  	def_bool n
+  
+@@ -1050,7 +1060,7 @@
+  	def_bool n
+  
+  config ATH79_DEV_GPIO_BUTTONS
+-@@ -164,4 +953,7 @@ config ATH79_PCI_ATH9K_FIXUP
++@@ -164,4 +962,7 @@ config ATH79_PCI_ATH9K_FIXUP
+  config ATH79_ROUTERBOOT
+  	def_bool n
+  
+@@ -1060,7 +1070,7 @@
+  endif
+ --- a/arch/mips/ath79/Makefile
+ +++ b/arch/mips/ath79/Makefile
+-@@ -38,9 +38,90 @@ obj-$(CONFIG_ATH79_ROUTERBOOT)		+= route
++@@ -38,9 +38,91 @@ obj-$(CONFIG_ATH79_ROUTERBOOT)		+= route
+  #
+  # Machines
+  #
+@@ -1079,6 +1089,7 @@
+ +obj-$(CONFIG_ATH79_MACH_AW_NR580)	+= mach-aw-nr580.o
+ +obj-$(CONFIG_ATH79_MACH_BHU_BXU2000N2_A)+= mach-bhu-bxu2000n2-a.o
+ +obj-$(CONFIG_ATH79_MACH_CAP4200AG)	+= mach-cap4200ag.o
+++obj-$(CONFIG_ATH79_MACH_CPE510)		+= mach-cpe510.o
+  obj-$(CONFIG_ATH79_MACH_DB120)		+= mach-db120.o
+ +obj-$(CONFIG_ATH79_MACH_DIR_505_A1)	+= mach-dir-505-a1.o
+ +obj-$(CONFIG_ATH79_MACH_DIR_600_A1)	+= mach-dir-600-a1.o
diff --git a/patches/openwrt/0007-ar71xx-refactor-ubnt-xw-board-setup.patch b/patches/openwrt/0007-ar71xx-refactor-ubnt-xw-board-setup.patch
new file mode 100644
index 0000000000000000000000000000000000000000..208e176633b6b1e556fdb7be0be82b167c49e151
--- /dev/null
+++ b/patches/openwrt/0007-ar71xx-refactor-ubnt-xw-board-setup.patch
@@ -0,0 +1,72 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Wed, 26 Nov 2014 23:20:33 +0100
+Subject: ar71xx: refactor ubnt xw board setup
+
+Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
+
+diff --git a/target/linux/ar71xx/patches-3.10/616-MIPS-ath79-ubnt-xw.patch b/target/linux/ar71xx/patches-3.10/616-MIPS-ath79-ubnt-xw.patch
+index ed2fd24..9413bd8 100644
+--- a/target/linux/ar71xx/patches-3.10/616-MIPS-ath79-ubnt-xw.patch
++++ b/target/linux/ar71xx/patches-3.10/616-MIPS-ath79-ubnt-xw.patch
+@@ -1,6 +1,8 @@
+---- a/arch/mips/ath79/mach-ubnt-xm.c
+-+++ b/arch/mips/ath79/mach-ubnt-xm.c
+-@@ -332,3 +332,60 @@ static void __init ubnt_uap_pro_setup(vo
++Index: linux-3.10.49/arch/mips/ath79/mach-ubnt-xm.c
++===================================================================
++--- linux-3.10.49.orig/arch/mips/ath79/mach-ubnt-xm.c	2014-08-15 22:55:37.890080659 +0200
+++++ linux-3.10.49/arch/mips/ath79/mach-ubnt-xm.c	2014-08-15 22:58:31.061570912 +0200
++@@ -332,3 +332,67 @@
+  MIPS_MACHINE(ATH79_MACH_UBNT_UAP_PRO, "UAP-PRO", "Ubiquiti UniFi AP Pro",
+  	     ubnt_uap_pro_setup);
+  
+@@ -29,7 +31,7 @@
+ +	},
+ +};
+ +
+-+static void __init ubnt_nano_m_xw_setup(void)
+++static void __init ubnt_xw_init(void)
+ +{
+ +	u8 *eeprom = (u8 *) KSEG1ADDR(0x1fff0000);
+ +
+@@ -44,26 +46,36 @@
+ +	ath79_register_wmac(eeprom + UAP_PRO_WMAC_CALDATA_OFFSET, NULL);
+ +	ap91_pci_init(eeprom + UAP_PRO_PCI_CALDATA_OFFSET, NULL);
+ +
+-+	ath79_register_mdio(0, ~(BIT(0) | BIT(1) | BIT(5)));
+ +
+ +	ath79_setup_ar934x_eth_cfg(AR934X_ETH_CFG_MII_GMAC0 | AR934X_ETH_CFG_MII_GMAC0_SLAVE);
+ +	ath79_init_mac(ath79_eth0_data.mac_addr,
+ +		       eeprom + UAP_PRO_MAC0_OFFSET, 0);
+ +
+-+	/* GMAC0 is connected to an AR8326 switch */
+ +	ath79_eth0_data.phy_if_mode = PHY_INTERFACE_MODE_MII;
+++	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+++}
+++
+++static void __init ubnt_nano_m_xw_setup(void)
+++{
+++	ubnt_xw_init();
+++
+++	/* GMAC0 is connected to an AR8326 switch */
+++	ath79_register_mdio(0, ~(BIT(0) | BIT(1) | BIT(5)));
+ +	ath79_eth0_data.phy_mask = (BIT(0) | BIT(1) | BIT(5));
+ +	ath79_eth0_data.speed = SPEED_100;
+ +	ath79_eth0_data.duplex = DUPLEX_FULL;
+-+	ath79_eth0_data.mii_bus_dev = &ath79_mdio0_device.dev;
+ +	ath79_register_eth(0);
+ +}
+ +
+ +MIPS_MACHINE(ATH79_MACH_UBNT_NANO_M_XW, "UBNT-NM-XW", "Ubiquiti Nanostation M XW",
+ +	     ubnt_nano_m_xw_setup);
+++
+ --- a/arch/mips/ath79/machtypes.h
+ +++ b/arch/mips/ath79/machtypes.h
+-@@ -124,6 +124,7 @@ enum ath79_mach_type {
++@@ -121,9 +121,10 @@ enum ath79_mach_type {
++ 	ATH79_MACH_TL_WR941ND,		/* TP-LINK TL-WR941ND */
++ 	ATH79_MACH_UBNT_AIRROUTER,	/* Ubiquiti AirRouter */
++ 	ATH79_MACH_UBNT_BULLET_M,	/* Ubiquiti Bullet M */
+  	ATH79_MACH_UBNT_LSSR71,		/* Ubiquiti LS-SR71 */
+  	ATH79_MACH_UBNT_LSX,		/* Ubiquiti LSX */
+  	ATH79_MACH_UBNT_NANO_M, 	/* Ubiquiti NanoStation M */
diff --git a/patches/openwrt/0008-ar71xx-add-board-support-for-ubnt-loco-m-xw.patch b/patches/openwrt/0008-ar71xx-add-board-support-for-ubnt-loco-m-xw.patch
new file mode 100644
index 0000000000000000000000000000000000000000..f154fa6c3e4d14488b0fb4a602ecc1995c1e37e3
--- /dev/null
+++ b/patches/openwrt/0008-ar71xx-add-board-support-for-ubnt-loco-m-xw.patch
@@ -0,0 +1,161 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Wed, 26 Nov 2014 23:20:46 +0100
+Subject: ar71xx: add board support for ubnt loco m xw
+
+Signed-off-by: Alexander Couzens <lynxis@fe80.eu>
+
+diff --git a/target/linux/ar71xx/base-files/etc/diag.sh b/target/linux/ar71xx/base-files/etc/diag.sh
+index 4b510dd..6e63343 100755
+--- a/target/linux/ar71xx/base-files/etc/diag.sh
++++ b/target/linux/ar71xx/base-files/etc/diag.sh
+@@ -34,7 +34,7 @@ get_status_led() {
+ 	aw-nr580)
+ 		status_led="aw-nr580:green:ready"
+ 		;;
+-	bullet-m | rocket-m | nano-m | nanostation-m | nanostation-m-xw)
++	bullet-m | rocket-m | nano-m | nanostation-m | nanostation-m-xw | loco-m-xw)
+ 		status_led="ubnt:green:link4"
+ 		;;
+ 	bxu2000n-2-a1)
+diff --git a/target/linux/ar71xx/base-files/etc/uci-defaults/01_leds b/target/linux/ar71xx/base-files/etc/uci-defaults/01_leds
+index fb8df40..8f845a0 100755
+--- a/target/linux/ar71xx/base-files/etc/uci-defaults/01_leds
++++ b/target/linux/ar71xx/base-files/etc/uci-defaults/01_leds
+@@ -38,7 +38,8 @@ ap113)
+ bullet-m | \
+ nanostation-m | \
+ rocket-m | \
+-nanostation-m-xw)
++nanostation-m-xw | \
++loco-m-xw)
+ 	ucidef_set_led_rssi "rssilow" "RSSILOW" "ubnt:red:link1" "wlan0" "1" "100" "0" "13"
+ 	ucidef_set_led_rssi "rssimediumlow" "RSSIMEDIUMLOW" "ubnt:orange:link2" "wlan0" "26" "100" "-25" "13"
+ 	ucidef_set_led_rssi "rssimediumhigh" "RSSIMEDIUMHIGH" "ubnt:green:link3" "wlan0" "51" "100" "-50" "13"
+diff --git a/target/linux/ar71xx/base-files/etc/uci-defaults/02_network b/target/linux/ar71xx/base-files/etc/uci-defaults/02_network
+index a9f00fa..5641a86 100755
+--- a/target/linux/ar71xx/base-files/etc/uci-defaults/02_network
++++ b/target/linux/ar71xx/base-files/etc/uci-defaults/02_network
+@@ -293,6 +293,7 @@ bullet-m |\
+ cap4200ag |\
+ eap300v2 |\
+ eap7660d |\
++loco-m-xw |\
+ mr600 |\
+ mr600v2 |\
+ rb-411 |\
+diff --git a/target/linux/ar71xx/base-files/lib/ar71xx.sh b/target/linux/ar71xx/base-files/lib/ar71xx.sh
+index 0b0a8d6..4e58efe 100755
+--- a/target/linux/ar71xx/base-files/lib/ar71xx.sh
++++ b/target/linux/ar71xx/base-files/lib/ar71xx.sh
+@@ -396,6 +396,9 @@ ar71xx_board_detect() {
+ 	*"Bullet M")
+ 		name="bullet-m"
+ 		;;
++	*"Loco M XW")
++		name="loco-m-xw"
++		;;
+ 	*"Nanostation M")
+ 		name="nanostation-m"
+ 		;;
+diff --git a/target/linux/ar71xx/base-files/lib/upgrade/platform.sh b/target/linux/ar71xx/base-files/lib/upgrade/platform.sh
+index 15e998c..7f02089 100755
+--- a/target/linux/ar71xx/base-files/lib/upgrade/platform.sh
++++ b/target/linux/ar71xx/base-files/lib/upgrade/platform.sh
+@@ -217,6 +217,7 @@ platform_check_image() {
+ 	airgateway | \
+ 	airrouter | \
+ 	bullet-m | \
++	loco-m-xw | \
+ 	nanostation-m | \
+ 	rocket-m | \
+ 	nanostation-m-xw | \
+diff --git a/target/linux/ar71xx/image/Makefile b/target/linux/ar71xx/image/Makefile
+index 5ff7f35..0d88ea5 100644
+--- a/target/linux/ar71xx/image/Makefile
++++ b/target/linux/ar71xx/image/Makefile
+@@ -1275,6 +1275,7 @@ $(eval $(call SingleProfile,UBNTXM,64kraw,UBNTNANOM,ubnt-nano-m,UBNT-NM,ttyS0,11
+ $(eval $(call SingleProfile,UBNTXM,64kraw,UBNTUNIFI,ubnt-unifi,UBNT-UF,ttyS0,115200,XM,BZ,ar7240))
+ $(eval $(call SingleProfile,UBNTXM,64kraw,UBNTUNIFIOUTDOOR,ubnt-unifi-outdoor,UBNT-U20,ttyS0,115200,XM,BZ,ar7240))
+ $(eval $(call SingleProfile,UBNTXM,64kraw,UBNTNANOMXW,ubnt-nano-m-xw,UBNT-NM-XW,ttyS0,115200,XM,XW,ar934x))
++$(eval $(call SingleProfile,UBNTXM,64kraw,UBNTLOCOXW,ubnt-loco-m-xw,UBNT-LOCO-XW,ttyS0,115200,XM,XW,ar934x))
+ $(eval $(call SingleProfile,UBNTXM,64kraw,UBNTAIRGW,ubnt-air-gateway,UBNT-AGW,ttyATH0,115200,XM,AirGW,ar933x))
+ 
+ $(eval $(call SingleProfile,WHRHPG300N,64kraw,WHRG301N,whr-g301n,WHR-G301N,ttyS0,115200,$$(whrhpg300n_mtdlayout),WHR-G301N))
+@@ -1320,7 +1321,7 @@ $(eval $(call MultiProfile,TLWR941,TLWR941NV2 TLWR941NV3 TLWR941NV4 TLWR941NV6))
+ $(eval $(call MultiProfile,TLWR1043,TLWR1043V1 TLWR1043V2))
+ $(eval $(call MultiProfile,TLWDR4300,TLWDR3500V1 TLWDR3600V1 TLWDR4300V1 TLWDR4300V1IL TLWDR4310V1 MW4530RV1))
+ $(eval $(call MultiProfile,TUBE2H,TUBE2H8M TUBE2H16M))
+-$(eval $(call MultiProfile,UBNT,UBNTAIRROUTER UBNTRS UBNTRSPRO UBNTLSSR71 UBNTBULLETM UBNTROCKETM UBNTNANOM UBNTNANOMXW UBNTUNIFI UBNTUNIFIOUTDOOR UAPPRO UBNTAIRGW))
++$(eval $(call MultiProfile,UBNT,UBNTAIRROUTER UBNTRS UBNTRSPRO UBNTLSSR71 UBNTBULLETM UBNTROCKETM UBNTNANOM UBNTNANOMXW UBNTLOCOXW UBNTUNIFI UBNTUNIFIOUTDOOR UAPPRO UBNTAIRGW))
+ $(eval $(call MultiProfile,WNDR3700,WNDR3700V1 WNDR3700V2 WNDR3800 WNDR3800CH WNDRMAC WNDRMACV2))
+ $(eval $(call MultiProfile,WNR612V2,REALWNR612V2 N150R))
+ $(eval $(call MultiProfile,WP543,WP543_2M WP543_4M WP543_8M WP543_16M))
+diff --git a/target/linux/ar71xx/patches-3.10/616-MIPS-ath79-ubnt-xw.patch b/target/linux/ar71xx/patches-3.10/616-MIPS-ath79-ubnt-xw.patch
+index 9413bd8..5e3d4d4 100644
+--- a/target/linux/ar71xx/patches-3.10/616-MIPS-ath79-ubnt-xw.patch
++++ b/target/linux/ar71xx/patches-3.10/616-MIPS-ath79-ubnt-xw.patch
+@@ -1,8 +1,6 @@
+-Index: linux-3.10.49/arch/mips/ath79/mach-ubnt-xm.c
+-===================================================================
+---- linux-3.10.49.orig/arch/mips/ath79/mach-ubnt-xm.c	2014-08-15 22:55:37.890080659 +0200
+-+++ linux-3.10.49/arch/mips/ath79/mach-ubnt-xm.c	2014-08-15 22:58:31.061570912 +0200
+-@@ -332,3 +332,67 @@
++--- a/arch/mips/ath79/mach-ubnt-xm.c
+++++ b/arch/mips/ath79/mach-ubnt-xm.c
++@@ -332,3 +332,78 @@ static void __init ubnt_uap_pro_setup(vo
+  MIPS_MACHINE(ATH79_MACH_UBNT_UAP_PRO, "UAP-PRO", "Ubiquiti UniFi AP Pro",
+  	     ubnt_uap_pro_setup);
+  
+@@ -67,15 +65,27 @@ Index: linux-3.10.49/arch/mips/ath79/mach-ubnt-xm.c
+ +	ath79_register_eth(0);
+ +}
+ +
+++static void __init ubnt_loco_m_xw_setup(void)
+++{
+++	ubnt_xw_init();
+++
+++	ath79_register_mdio(0, ~BIT(1));
+++	ath79_eth0_data.phy_mask = BIT(1);
+++	ath79_register_eth(0);
+++}
+++
+ +MIPS_MACHINE(ATH79_MACH_UBNT_NANO_M_XW, "UBNT-NM-XW", "Ubiquiti Nanostation M XW",
+ +	     ubnt_nano_m_xw_setup);
+ +
+++MIPS_MACHINE(ATH79_MACH_UBNT_LOCO_M_XW, "UBNT-LOCO-XW", "Ubiquiti Loco M XW",
+++	     ubnt_loco_m_xw_setup);
+ --- a/arch/mips/ath79/machtypes.h
+ +++ b/arch/mips/ath79/machtypes.h
+-@@ -121,9 +121,10 @@ enum ath79_mach_type {
++@@ -121,9 +121,11 @@ enum ath79_mach_type {
+  	ATH79_MACH_TL_WR941ND,		/* TP-LINK TL-WR941ND */
+  	ATH79_MACH_UBNT_AIRROUTER,	/* Ubiquiti AirRouter */
+  	ATH79_MACH_UBNT_BULLET_M,	/* Ubiquiti Bullet M */
+++	ATH79_MACH_UBNT_LOCO_M_XW, 	/* Ubiquiti Loco M XW */
+  	ATH79_MACH_UBNT_LSSR71,		/* Ubiquiti LS-SR71 */
+  	ATH79_MACH_UBNT_LSX,		/* Ubiquiti LSX */
+  	ATH79_MACH_UBNT_NANO_M, 	/* Ubiquiti NanoStation M */
+diff --git a/target/linux/ar71xx/patches-3.10/722-MIPS-ath79-add-airGateway-support.patch b/target/linux/ar71xx/patches-3.10/722-MIPS-ath79-add-airGateway-support.patch
+index 0fe62d9..c9d1e1e 100644
+--- a/target/linux/ar71xx/patches-3.10/722-MIPS-ath79-add-airGateway-support.patch
++++ b/target/linux/ar71xx/patches-3.10/722-MIPS-ath79-add-airGateway-support.patch
+@@ -12,10 +12,10 @@
+  #include "dev-ap9x-pci.h"
+  #include "dev-eth.h"
+  #include "dev-gpio-buttons.h"
+-@@ -389,3 +391,65 @@ static void __init ubnt_nano_m_xw_setup(
++@@ -406,3 +408,65 @@ MIPS_MACHINE(ATH79_MACH_UBNT_NANO_M_XW,
+  
+- MIPS_MACHINE(ATH79_MACH_UBNT_NANO_M_XW, "UBNT-NM-XW", "Ubiquiti Nanostation M XW",
+- 	     ubnt_nano_m_xw_setup);
++ MIPS_MACHINE(ATH79_MACH_UBNT_LOCO_M_XW, "UBNT-LOCO-XW", "Ubiquiti Loco M XW",
++ 	     ubnt_loco_m_xw_setup);
+ +
+ +static struct gpio_led ubnt_airgateway_gpio_leds[] __initdata = {
+ +	{
+@@ -87,4 +87,4 @@
+ +	ATH79_MACH_UBNT_AIRGW,		/* Ubiquiti AirGateway */
+  	ATH79_MACH_UBNT_AIRROUTER,	/* Ubiquiti AirRouter */
+  	ATH79_MACH_UBNT_BULLET_M,	/* Ubiquiti Bullet M */
+- 	ATH79_MACH_UBNT_LSSR71,		/* Ubiquiti LS-SR71 */
++ 	ATH79_MACH_UBNT_LOCO_M_XW, 	/* Ubiquiti Loco M XW */
diff --git a/patches/openwrt/0009-busybox-enable-telnet-only-when-root-password-is-really-empty-not-when-it-is-locked.patch b/patches/openwrt/0009-busybox-enable-telnet-only-when-root-password-is-really-empty-not-when-it-is-locked.patch
new file mode 100644
index 0000000000000000000000000000000000000000..772ade629143ecef46c218575fa172076dce6c7c
--- /dev/null
+++ b/patches/openwrt/0009-busybox-enable-telnet-only-when-root-password-is-really-empty-not-when-it-is-locked.patch
@@ -0,0 +1,26 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Fri, 5 Dec 2014 18:57:16 +0100
+Subject: busybox: enable telnet only when root password is really empty, not when it is locked
+
+diff --git a/package/utils/busybox/files/telnet b/package/utils/busybox/files/telnet
+index a1d1cdf..f95be90 100755
+--- a/package/utils/busybox/files/telnet
++++ b/package/utils/busybox/files/telnet
+@@ -11,7 +11,7 @@ has_root_pwd() {
+ 	      pwd="${pwd#*root:}"
+ 	      pwd="${pwd%%:*}"
+ 
+-	test -n "${pwd#[\!x]}"
++	test -n "${pwd}"
+ }
+ 
+ get_root_home() {
+@@ -28,7 +28,7 @@ has_ssh_pubkey() {
+ 
+ start_service() {
+ 	if ( ! has_ssh_pubkey && \
+-	     ! has_root_pwd /etc/passwd && ! has_root_pwd /etc/shadow ) || \
++	   ( ! has_root_pwd /etc/passwd || ! has_root_pwd /etc/shadow ) ) || \
+ 	   ( ! /etc/init.d/dropbear enabled 2> /dev/null && ! /etc/init.d/sshd enabled 2> /dev/null );
+ 	then
+ 		procd_open_instance
diff --git a/patches/openwrt/0010-ar71xx-add-workaround-patch-for-WDR3600-4300-reboot.patch b/patches/openwrt/0010-ar71xx-add-workaround-patch-for-WDR3600-4300-reboot.patch
new file mode 100644
index 0000000000000000000000000000000000000000..a0589145496652260b362cec7c0a8be3428a062e
--- /dev/null
+++ b/patches/openwrt/0010-ar71xx-add-workaround-patch-for-WDR3600-4300-reboot.patch
@@ -0,0 +1,24 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Mon, 15 Dec 2014 00:17:38 +0100
+Subject: ar71xx: add workaround patch for WDR3600/4300 reboot
+
+While it isn't clear why this patch helps, it doesn't seem to have any negative
+effects, so let's include it for now...
+
+diff --git a/target/linux/ar71xx/patches-3.10/903-MIPS-ath79-fix-restart.patch b/target/linux/ar71xx/patches-3.10/903-MIPS-ath79-fix-restart.patch
+new file mode 100644
+index 0000000..86f33f3
+--- /dev/null
++++ b/target/linux/ar71xx/patches-3.10/903-MIPS-ath79-fix-restart.patch
+@@ -0,0 +1,11 @@
++--- a/arch/mips/ath79/common.c
+++++ b/arch/mips/ath79/common.c
++@@ -83,6 +83,8 @@ void ath79_device_reset_set(u32 mask)
++ 	spin_lock_irqsave(&ath79_device_reset_lock, flags);
++ 	t = ath79_reset_rr(reg);
++ 	ath79_reset_wr(reg, t | mask);
+++	if (mask == AR71XX_RESET_FULL_CHIP)
+++		for(;;);
++ 	spin_unlock_irqrestore(&ath79_device_reset_lock, flags);
++ }
++ EXPORT_SYMBOL_GPL(ath79_device_reset_set);
diff --git a/patches/packages/openwrt/0002-fastd-update-to-v16.patch b/patches/packages/openwrt/0002-fastd-update-to-v16.patch
new file mode 100644
index 0000000000000000000000000000000000000000..caaa5bd6ffffa7fd0cc43641e56ca4592b613cba
--- /dev/null
+++ b/patches/packages/openwrt/0002-fastd-update-to-v16.patch
@@ -0,0 +1,100 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sat, 15 Nov 2014 18:50:34 +0100
+Subject: fastd: update to v16
+
+diff --git a/net/fastd/Config.in b/net/fastd/Config.in
+index ca4045c..8292245 100644
+--- a/net/fastd/Config.in
++++ b/net/fastd/Config.in
+@@ -80,8 +80,14 @@ config FASTD_WITH_CMDLINE_COMMANDS
+ 	default n
+ 
+ config FASTD_WITH_VERIFY
+-        bool "Include support for on-verify handlers"
+-        depends on PACKAGE_fastd
+-        default n
++	bool "Include support for on-verify handlers"
++	depends on PACKAGE_fastd
++	default n
++
++config FASTD_WITH_STATUS_SOCKET
++	bool "Include support for status sockets"
++	depends on PACKAGE_fastd
++	default y
++
+ 
+ endmenu
+diff --git a/net/fastd/Makefile b/net/fastd/Makefile
+index 0629cd7..acf973b 100644
+--- a/net/fastd/Makefile
++++ b/net/fastd/Makefile
+@@ -8,13 +8,16 @@
+ include $(TOPDIR)/rules.mk
+ 
+ PKG_NAME:=fastd
+-PKG_VERSION:=14
++PKG_VERSION:=16
+ PKG_RELEASE:=1
+ 
+ PKG_MAINTAINER:=Matthias Schiffer <mschiffer@universe-factory.net>
+ PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+-PKG_SOURCE_URL:=https://projects.universe-factory.net/attachments/download/75
+-PKG_MD5SUM:=34f6bdebd0410a1fba7c8fd06fff7a05
++PKG_SOURCE_URL:=https://projects.universe-factory.net/attachments/download/78
++PKG_MD5SUM:=135b3083d2743e335738de3bd4bb0c3c
++
++PKG_LICENSE:=BSD-2-Clause
++PKG_LICENSE_FILE:=COPYRIGHT
+ 
+ PKG_CONFIG_DEPENDS:=\
+ 	CONFIG_FASTD_ENABLE_METHOD_CIPHER_TEST \
+@@ -32,7 +35,8 @@ PKG_CONFIG_DEPENDS:=\
+ 	CONFIG_FASTD_WITH_CMDLINE_LOGGING \
+ 	CONFIG_FASTD_WITH_CMDLINE_OPERATION \
+ 	CONFIG_FASTD_WITH_CMDLINE_COMMANDS \
+-	CONFIG_FASTD_WITH_VERIFY
++	CONFIG_FASTD_WITH_VERIFY \
++	CONFIG_FASTD_WITH_STATUS_SOCKET
+ 
+ 
+ PKG_BUILD_DEPENDS:=nacl libuecc
+@@ -43,7 +47,7 @@ include $(INCLUDE_DIR)/cmake.mk
+ define Package/fastd
+   SECTION:=net
+   CATEGORY:=Network
+-  DEPENDS:=+kmod-tun +librt +libpthread
++  DEPENDS:=+kmod-tun +librt +libpthread +FASTD_WITH_STATUS_SOCKET:libjson-c
+   TITLE:=Fast and Secure Tunneling Daemon
+   URL:=https://projects.universe-factory.net/projects/fastd
+   SUBMENU:=VPN
+@@ -74,6 +78,7 @@ CMAKE_OPTIONS += \
+ 	-DWITH_CMDLINE_OPERATION:BOOL=FALSE \
+ 	-DWITH_CMDLINE_COMMANDS:BOOL=FALSE \
+ 	-DWITH_VERIFY:BOOL=FALSE \
++	-DWITH_STATUS_SOCKET:BOOL=FALSE \
+ 	-DWITH_CAPABILITIES:BOOL=FALSE \
+ 	-DENABLE_SYSTEMD:BOOL=FALSE \
+ 	-DENABLE_LIBSODIUM:BOOL=FALSE \
+@@ -147,6 +152,10 @@ ifeq ($(CONFIG_FASTD_WITH_VERIFY),y)
+ CMAKE_OPTIONS += -DWITH_VERIFY:BOOL=TRUE
+ endif
+ 
++ifeq ($(CONFIG_FASTD_WITH_STATUS_SOCKET),y)
++CMAKE_OPTIONS += -DWITH_STATUS_SOCKET:BOOL=TRUE
++endif
++
+ 
+ define Package/fastd/description
+  Fast and secure tunneling daemon, which is optimized on small code size and few dependencies
+@@ -161,9 +170,9 @@ define Package/fastd/install
+ 	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/fastd $(1)/usr/bin/
+ 
+ 	$(INSTALL_DIR) $(1)/etc/init.d/
+-	$(INSTALL_BIN) files/fastd.init $(1)/etc/init.d/fastd
++	$(INSTALL_BIN) $(PKG_BUILD_DIR)/doc/examples/openwrt/fastd.init $(1)/etc/init.d/fastd
+ 	$(INSTALL_DIR) $(1)/etc/config
+-	$(INSTALL_CONF) files/fastd.config $(1)/etc/config/fastd
++	$(INSTALL_CONF) $(PKG_BUILD_DIR)/doc/examples/openwrt/fastd.config $(1)/etc/config/fastd
+ 	$(INSTALL_DIR) $(1)/etc/fastd
+ 	$(INSTALL_DIR) $(1)/lib/upgrade/keep.d
+ 	$(INSTALL_DATA) files/fastd.upgrade $(1)/lib/upgrade/keep.d/fastd
diff --git a/patches/packages/routing/0003-batman-adv-introduce-no_rebroadcast-option.patch b/patches/packages/routing/0003-batman-adv-introduce-no_rebroadcast-option.patch
index 8b861ab1203905f0f7d5f35a69486095c21f7a62..62b19dae4e5bf6e7994bd678d664839e6a287581 100644
--- a/patches/packages/routing/0003-batman-adv-introduce-no_rebroadcast-option.patch
+++ b/patches/packages/routing/0003-batman-adv-introduce-no_rebroadcast-option.patch
@@ -4,12 +4,12 @@ Subject: batman-adv: introduce 'no_rebroadcast' option
 
 diff --git a/batman-adv/patches/0001-batman-adv-introduce-no_rebroadcast-option.patch b/batman-adv/patches/0001-batman-adv-introduce-no_rebroadcast-option.patch
 new file mode 100644
-index 0000000..4f2da9a
+index 0000000..cb5c633
 --- /dev/null
 +++ b/batman-adv/patches/0001-batman-adv-introduce-no_rebroadcast-option.patch
 @@ -0,0 +1,185 @@
-+From 382460a7114b734581970076d4dfe3011381e339 Mon Sep 17 00:00:00 2001
-+Message-Id: <382460a7114b734581970076d4dfe3011381e339.1408708010.git.mschiffer@universe-factory.net>
++From 0c8001036a191efd3aa30493ba7e31f9eceb21e1 Mon Sep 17 00:00:00 2001
++Message-Id: <0c8001036a191efd3aa30493ba7e31f9eceb21e1.1418604208.git.mschiffer@universe-factory.net>
 +From: =?UTF-8?q?Linus=20L=C3=BCssing?= <linus.luessing@web.de>
 +Date: Tue, 24 Sep 2013 04:36:27 +0200
 +Subject: [PATCH] batman-adv: introduce 'no_rebroadcast' option
@@ -45,7 +45,7 @@ index 0000000..4f2da9a
 + 5 files changed, 76 insertions(+)
 +
 +diff --git a/hard-interface.c b/hard-interface.c
-+index b851cc5..b222d82 100644
++index fbda6b5..3997f9c 100644
 +--- a/hard-interface.c
 ++++ b/hard-interface.c
 +@@ -591,6 +591,8 @@ batadv_hardif_add_interface(struct net_device *net_dev)
@@ -91,12 +91,12 @@ index 0000000..4f2da9a
 ++                or wired links. Using this option wrongly is going to
 ++                break your mesh network, use at your own risk!
 +diff --git a/sysfs.c b/sysfs.c
-+index 1ebb0d9..780c52e 100644
++index fc47baa..adaeca4 100644
 +--- a/sysfs.c
 ++++ b/sysfs.c
-+@@ -108,6 +108,17 @@ struct batadv_attribute batadv_attr_vlan_##_name = {	\
++@@ -110,6 +110,17 @@ struct batadv_attribute batadv_attr_vlan_##_name = {	\
 + 	.store  = _store,				\
-+ };
++ }
 + 
 ++/* Use this, if you have customized show and store functions
 ++ * for hard interface attrs
@@ -112,7 +112,7 @@ index 0000000..4f2da9a
 + /* Use this, if you have customized show and store functions */
 + #define BATADV_ATTR(_name, _mode, _show, _store)	\
 + struct batadv_attribute batadv_attr_##_name = {		\
-+@@ -213,6 +224,52 @@ ssize_t batadv_show_vlan_##_name(struct kobject *kobj,			\
++@@ -221,6 +232,52 @@ ssize_t batadv_show_vlan_##_name(struct kobject *kobj,			\
 + 	static BATADV_ATTR_VLAN(_name, _mode, batadv_show_vlan_##_name,	\
 + 				batadv_store_vlan_##_name)
 + 
@@ -165,7 +165,7 @@ index 0000000..4f2da9a
 + static int batadv_store_bool_attr(char *buff, size_t count,
 + 				  struct net_device *net_dev,
 + 				  const char *attr_name, atomic_t *attr)
-+@@ -834,10 +891,12 @@ static ssize_t batadv_show_iface_status(struct kobject *kobj,
++@@ -844,10 +901,12 @@ static ssize_t batadv_show_iface_status(struct kobject *kobj,
 + static BATADV_ATTR(mesh_iface, S_IRUGO | S_IWUSR, batadv_show_mesh_iface,
 + 		   batadv_store_mesh_iface);
 + static BATADV_ATTR(iface_status, S_IRUGO, batadv_show_iface_status, NULL);
@@ -191,5 +191,5 @@ index 0000000..4f2da9a
 + 
 + /**
 +-- 
-+2.1.0
++2.1.3
 +
diff --git a/patches/packages/routing/0004-batman-adv-add-two-more-patches-from-the-upstream-maint-branch.patch b/patches/packages/routing/0004-batman-adv-add-two-more-patches-from-the-upstream-maint-branch.patch
new file mode 100644
index 0000000000000000000000000000000000000000..8230e61c1a3f97ee92e6403c9f92de7d55edf467
--- /dev/null
+++ b/patches/packages/routing/0004-batman-adv-add-two-more-patches-from-the-upstream-maint-branch.patch
@@ -0,0 +1,126 @@
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Mon, 15 Dec 2014 01:44:23 +0100
+Subject: batman-adv: add two more patches from the upstream 'maint' branch
+
+diff --git a/batman-adv/patches/0002-batman-adv-Fix-double-fetch-in-RCU-version-of-hlist_.patch b/batman-adv/patches/0002-batman-adv-Fix-double-fetch-in-RCU-version-of-hlist_.patch
+new file mode 100644
+index 0000000..6fb2e63
+--- /dev/null
++++ b/batman-adv/patches/0002-batman-adv-Fix-double-fetch-in-RCU-version-of-hlist_.patch
+@@ -0,0 +1,54 @@
++From 2cbadf647c3836ad1cf62ec5554fbeee7b3d6ecd Mon Sep 17 00:00:00 2001
++Message-Id: <2cbadf647c3836ad1cf62ec5554fbeee7b3d6ecd.1418604208.git.mschiffer@universe-factory.net>
++In-Reply-To: <0c8001036a191efd3aa30493ba7e31f9eceb21e1.1418604208.git.mschiffer@universe-factory.net>
++References: <0c8001036a191efd3aa30493ba7e31f9eceb21e1.1418604208.git.mschiffer@universe-factory.net>
++From: Sven Eckelmann <sven@narfation.org>
++Date: Mon, 3 Nov 2014 23:16:19 +0100
++Subject: [PATCH] batman-adv: Fix double fetch in RCU version of hlist_*entry*
++
++The backported (<3.9) version of hlist_for_each_entry_rcu and
++hlist_for_each_entry_safe uses the new macro hlist_entry_safe. It is called
++with an ACCESS_ONCE parameter for the first parameter ptr. This disallows
++merging of the two loads which the current version of the macro uses.
++
++This is problematic because this macro must only generate one load. Otherwise
++with two contexts (or CPUs) following could happen:
++
++1. context 1 fetches the ptr to the last entry in hlist_entry_safe() and
++   accepts this non-NULL ptr
++
++2. context 2 deletes the last entry and terminates the list with NULL
++
++3. context 1 re-fetches the pointer, doesn't check for zero, calculates the
++   entry based on a NULL pointer
++
++4. context 1 crashes because it tries to load/write data from/to the invalid
++   address
++
++Instead use a single load to a temporary variable and do the NULL-check and
++calculation based on that one.
++
++Signed-off-by: Sven Eckelmann <sven@narfation.org>
++Signed-off-by: Marek Lindner <mareklindner@neomailbox.ch>
++---
++ compat.h | 4 +++-
++ 1 file changed, 3 insertions(+), 1 deletion(-)
++
++diff --git a/compat.h b/compat.h
++index 5eb5fe6..79ba39b 100644
++--- a/compat.h
+++++ b/compat.h
++@@ -345,7 +345,9 @@ static int __batadv_interface_tx(struct sk_buff *skb, \
++ 	dev->master;\
++ })
++ #define hlist_entry_safe(ptr, type, member) \
++-	(ptr) ? hlist_entry(ptr, type, member) : NULL
+++	({ typeof(ptr) ____ptr = (ptr); \
+++	   ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
+++	})
++ 
++ #undef hlist_for_each_entry
++ #define hlist_for_each_entry(pos, head, member) \
++-- 
++2.1.3
++
+diff --git a/batman-adv/patches/0003-batman-adv-fix-delayed-foreign-originator-recognitio.patch b/batman-adv/patches/0003-batman-adv-fix-delayed-foreign-originator-recognitio.patch
+new file mode 100644
+index 0000000..2748f76
+--- /dev/null
++++ b/batman-adv/patches/0003-batman-adv-fix-delayed-foreign-originator-recognitio.patch
+@@ -0,0 +1,56 @@
++From 207d13673fd25e5ae1bc8bb42d1efd4ec4c2dc4d Mon Sep 17 00:00:00 2001
++Message-Id: <207d13673fd25e5ae1bc8bb42d1efd4ec4c2dc4d.1418604208.git.mschiffer@universe-factory.net>
++In-Reply-To: <0c8001036a191efd3aa30493ba7e31f9eceb21e1.1418604208.git.mschiffer@universe-factory.net>
++References: <0c8001036a191efd3aa30493ba7e31f9eceb21e1.1418604208.git.mschiffer@universe-factory.net>
++From: =?UTF-8?q?Linus=20L=C3=BCssing?= <linus.luessing@c0d3.blue>
++Date: Thu, 30 Oct 2014 06:23:40 +0100
++Subject: [PATCH] batman-adv: fix delayed foreign originator recognition
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Currently it can happen that the reception of an OGM from a new
++originator is not being accepted. More precisely it can happen that
++an originator struct gets allocated and initialized
++(batadv_orig_node_new()), even the TQ gets calculated and set correctly
++(batadv_iv_ogm_calc_tq()) but still the periodic orig_node purging
++thread will decide to delete it if it has a chance to jump between
++these two function calls.
++
++This is because batadv_orig_node_new() initializes the last_seen value
++to zero and its caller (batadv_iv_ogm_orig_get()) makes it visible to
++other threads by adding it to the hash table already.
++batadv_iv_ogm_calc_tq() will set the last_seen variable to the correct,
++current time a few lines later but if the purging thread jumps in between
++that it will think that the orig_node timed out and will wrongly
++schedule it for deletion already.
++
++If the purging interval is the same as the originator interval (which is
++the default: 1 second), then this game can continue for several rounds
++until the random OGM jitter added enough difference between these
++two (in tests, two to about four rounds seemed common).
++
++Fixing this by initializing the last_seen variable of an orig_node
++to the current time before adding it to the hash table.
++
++Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
++Signed-off-by: Marek Lindner <mareklindner@neomailbox.ch>
++---
++ originator.c | 1 +
++ 1 file changed, 1 insertion(+)
++
++diff --git a/originator.c b/originator.c
++index 6a48451..648bdba 100644
++--- a/originator.c
+++++ b/originator.c
++@@ -678,6 +678,7 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
++ 	atomic_set(&orig_node->last_ttvn, 0);
++ 	orig_node->tt_buff = NULL;
++ 	orig_node->tt_buff_len = 0;
+++	orig_node->last_seen = jiffies;
++ 	reset_time = jiffies - 1 - msecs_to_jiffies(BATADV_RESET_PROTECTION_MS);
++ 	orig_node->bcast_seqno_reset = reset_time;
++ #ifdef CONFIG_BATMAN_ADV_MCAST
++-- 
++2.1.3
++
diff --git a/targets/ar71xx-generic/kernel-config b/targets/ar71xx-generic/kernel-config
index b216d158daf462c847af848bf6b0f523c8bbf20e..2c97a96d5623cfca14273693787919907379a314 100644
--- a/targets/ar71xx-generic/kernel-config
+++ b/targets/ar71xx-generic/kernel-config
@@ -68,6 +68,7 @@ CONFIG_ATH79_MACH_AP136=y
 CONFIG_ATH79_MACH_AP81=y
 CONFIG_ATH79_MACH_AP83=y
 CONFIG_ATH79_MACH_AP96=y
+CONFIG_ATH79_MACH_CPE510=y
 CONFIG_ATH79_MACH_DB120=y
 CONFIG_ATH79_MACH_PB42=y
 CONFIG_ATH79_MACH_PB44=y
diff --git a/targets/ar71xx-generic/profiles.mk b/targets/ar71xx-generic/profiles.mk
index de63e7cc5f864bd82feb3e269b1ed492a17dcb0a..0a3935e076ebf99ed0e6b40423474cc9e303145e 100644
--- a/targets/ar71xx-generic/profiles.mk
+++ b/targets/ar71xx-generic/profiles.mk
@@ -2,6 +2,13 @@
 
 ## TP-Link
 
+# CPE210/220/510/520
+$(eval $(call GluonProfile,CPE510,rssileds))
+$(eval $(call GluonModel,CPE510,cpe210-220-510-520-squashfs,tp-link-cpe210-v1.0))
+$(eval $(call GluonModel,CPE510,cpe210-220-510-520-squashfs,tp-link-cpe220-v1.0))
+$(eval $(call GluonModel,CPE510,cpe210-220-510-520-squashfs,tp-link-cpe510-v1.0))
+$(eval $(call GluonModel,CPE510,cpe210-220-510-520-squashfs,tp-link-cpe520-v1.0))
+
 # TL-WR703N v1
 $(eval $(call GluonProfile,TLWR703))
 $(eval $(call GluonModel,TLWR703,tl-wr703n-v1-squashfs,tp-link-tl-wr703n-v1))
@@ -100,15 +107,13 @@ $(eval $(call GluonModel,UBNT,ubnt-unifi-squashfs,ubiquiti-unifi))
 $(eval $(call GluonModel,UBNT,ubnt-unifi-outdoor-squashfs,ubiquiti-unifiap-outdoor))
 ifeq ($(BROKEN),1)
 $(eval $(call GluonModel,UBNT,ubnt-uap-pro-squashfs,ubiquiti-unifi-ap-pro))
+$(eval $(call GluonModel,UBNT,ubnt-nano-m-xw-squashfs,ubiquiti-nanostation-m-xw))
+$(eval $(call GluonModel,UBNT,ubnt-loco-m-xw-squashfs,ubiquiti-loco-m-xw))
 endif
 
 
 ## D-Link
 
-# D-Link DIR-615 rev. E1
-#$(eval $(call GluonProfile,DIR615E1))
-#$(eval $(call GluonModel,DIR615E1,dir-615-e1-squashfs,d-link-dir-615-rev-e1))
-
 # D-Link DIR-825 rev. B1
 $(eval $(call GluonProfile,DIR825B1))
 $(eval $(call GluonModel,DIR825B1,dir-825-b1-squashfs,d-link-dir-825-rev-b1))